aboutsummaryrefslogtreecommitdiff
path: root/VKPC/PopoverController.m
diff options
context:
space:
mode:
Diffstat (limited to 'VKPC/PopoverController.m')
-rw-r--r--VKPC/PopoverController.m449
1 files changed, 449 insertions, 0 deletions
diff --git a/VKPC/PopoverController.m b/VKPC/PopoverController.m
new file mode 100644
index 0000000..146cf5e
--- /dev/null
+++ b/VKPC/PopoverController.m
@@ -0,0 +1,449 @@
+//
+// PopoverViewController.m
+// VKPC
+//
+// Created by Eugene on 11/30/13.
+// Copyright (c) 2013-2014 Eugene Z. All rights reserved.
+//
+
+#import "Popover.h"
+#import "PopoverController.h"
+#import "FlippedView.h"
+#import "AboutWindowController.h"
+#import "PlaylistTableController.h"
+#import "NSMutableArray+QueueAdditions.h"
+#import "Controller.h"
+//#import "HostsHack.h"
+#import "Playlist.h"
+#import "Server.h"
+#import "Autostart.h"
+#import "CatchMediaButtons.h"
+#import "Statistics.h"
+
+#import "PlaylistTableView.h"
+#import "PlaylistTableCellView.h"
+#import "ShadowTextFieldCell.h"
+#import "VibrantTextField.h"
+
+static const int kMinPopoverHeight = 240;
+static const int kMaxPopoverHeight = 480;
+
+static NSInteger NSStateFromBool(BOOL v) {
+ return v ? NSOnState : NSOffState;
+}
+static BOOL BoolFromNSState(NSInteger state) {
+ return state == NSOffState ? NO : YES;
+}
+static NSInteger InvertNSState(NSInteger state) {
+ return state == NSOffState ? NSOnState : NSOffState;
+}
+
+@implementation PopoverController {
+ int setHeightOnShow;
+ AboutWindowController *aboutWindowController;
+}
+
++ (PopoverController *)shared {
+ static PopoverController *shared = nil;
+ @synchronized (self) {
+ if (shared == nil){
+ shared = [[self alloc] initWithNibName:@"PopoverView" bundle:nil];
+ }
+ }
+ return shared;
+}
+
+- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
+ if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
+ _state = PopoverStatePlaylistNotLoaded;
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ NSLog(@"[PopoverController awakeFromNib]");
+
+ [super awakeFromNib];
+ [self updateStyle];
+
+ // Load settings
+ BOOL catchMediaButtons = [[NSUserDefaults standardUserDefaults] boolForKey:VKPCPreferencesCatchMediaButtons];
+ BOOL invertPlaylistIcons = [[NSUserDefaults standardUserDefaults] boolForKey:VKPCPreferencesInvertPlaylistIcons];
+ BOOL showNotifications = [[NSUserDefaults standardUserDefaults] boolForKey:VKPCPreferencesShowNotifications];
+ BOOL launchOnStartup = [Autostart isLaunchAtStartup];
+ BOOL useExtensionMode = [[NSUserDefaults standardUserDefaults] boolForKey:VKPCPreferencesUseExtensionMode];
+ NSInteger browser = [[NSUserDefaults standardUserDefaults] integerForKey:VKPCPreferencesBrowser];
+
+ [_menuItemCatch setState:NSStateFromBool(catchMediaButtons)];
+ [_menuItemInvert setState:NSStateFromBool(invertPlaylistIcons)];
+ [_menuItemShowNotifications setState:NSStateFromBool(showNotifications)];
+ [_menuItemAutostart setState:NSStateFromBool(launchOnStartup)];
+ [_useExtensionMode setState:NSStateFromBool(useExtensionMode)];
+ [self useExtensionModeUpdated];
+
+ if (browser < [_browserMenu itemArray].count && browser >= 0) {
+ [(NSMenuItem *)[_browserMenu itemArray][browser] setState:NSOnState];
+ } else {
+ [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:VKPCPreferencesBrowser];
+ [(NSMenuItem *)[_browserMenu itemArray][0] setState:NSOnState];
+ }
+
+ //
+ _playlistTableController = [[PlaylistTableController alloc] init];
+ setHeightOnShow = -1;
+
+ if (VKPCIsYosemite) {
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(darkModeChanged:) name:kAppleInterfaceThemeChangedNotification object:nil];
+ }
+
+ [[NSUserDefaults standardUserDefaults] addObserver:self
+ forKeyPath:VKPCPreferencesInvertPlaylistIcons
+ options:NSKeyValueObservingOptionNew
+ context:NULL];
+
+ [self updateState];
+
+#ifdef DEBUG
+ NSArray *debugMenuItems = @[
+ [[NSMenuItem alloc] initWithTitle:@"Inject script" action:@selector(menuInjectAction:) keyEquivalent:@"inject"],
+ [[NSMenuItem alloc] initWithTitle:@"Send 'play' command" action:@selector(menuSendPlayAction:) keyEquivalent:@"send_play"],
+ [[NSMenuItem alloc] initWithTitle:@"JS to clipboard" action:@selector(menuJSToClipboardAction:) keyEquivalent:@"copy_js"],
+ [[NSMenuItem alloc] initWithTitle:@"AS to clipboard" action:@selector(menuASToClipboardAction:) keyEquivalent:@"copy_as"],
+ [[NSMenuItem alloc] initWithTitle:@"Notification after 1 sec" action:@selector(menuNotificationAction:) keyEquivalent:@"notification"],
+ [[NSMenuItem alloc] initWithTitle:@"Add tracks" action:@selector(menuAddTracksAction:) keyEquivalent:@"add_tracks"],
+ [[NSMenuItem alloc] initWithTitle:@"Remove tracks" action:@selector(menuRemoveTracksAction:) keyEquivalent:@"remove_tracks"],
+// [[NSMenuItem alloc] initWithTitle:@"Show HH window" action:@selector(menuShowHHWindowAction:) keyEquivalent:@"show_hh"],
+ [[NSMenuItem alloc] initWithTitle:@"Print debug info" action:@selector(menuPrintDebugInfoAction:) keyEquivalent:@"print_debug_info"],
+ [[NSMenuItem alloc] initWithTitle:@"Something" action:@selector(menuSomethingAction:) keyEquivalent:@"something"]
+ ];
+
+ for (NSMenuItem *item in debugMenuItems) {
+ [_appMenu insertItem:item atIndex:[_appMenu itemArray].count-3];
+ }
+ [_appMenu insertItem:[NSMenuItem separatorItem] atIndex:[_appMenu itemArray].count-3];
+#endif
+}
+
+// UI
+
+- (void)setState:(PopoverState)state {
+ _state = state;
+ [self updateState];
+}
+
+- (void)updateState {
+ switch (_state) {
+ case PopoverStatePlaylistNotLoaded:
+ [_customView setHidden:NO];
+// [_systemConfigurationRequiredButton setHidden:YES];
+ [_playlistNotLoadedTextField setHidden:NO];
+ break;
+
+ case PopoverStatePlaylistLoaded:
+ [_customView setHidden:YES];
+ break;
+
+ case PopoverStateSystemConfigurationRequired:
+ [_customView setHidden:NO];
+ [_playlistNotLoadedTextField setHidden:YES];
+// [_systemConfigurationRequiredButton setHidden:NO];
+ break;
+ }
+}
+
+- (void)resizeWithContentHeight:(int)height {
+ NSPopover *popover = [[Popover shared] popover];
+ if (!popover.isShown)
+ setHeightOnShow = height;
+ //else
+ [self doResizeWithContentHeight:height animate:popover.isShown];
+}
+
+- (void)doResizeWithContentHeight:(int)height animate:(BOOL)animate {
+ NSRect scrollViewFrame = self.scrollView.frame;
+ int scrollViewYOffset = scrollViewFrame.origin.y;
+
+ int popoverHeight = height + scrollViewYOffset;
+ if (popoverHeight > kMaxPopoverHeight) popoverHeight = kMaxPopoverHeight;
+ if (popoverHeight < kMinPopoverHeight) popoverHeight = kMinPopoverHeight;
+
+ NSSize popoverSize = [[Popover shared] getSize];
+ [[Popover shared] setSize:NSMakeSize(popoverSize.width, popoverHeight) animate:animate];
+ [[self scrollView] setFrame:NSMakeRect(scrollViewFrame.origin.x, scrollViewFrame.origin.y, scrollViewFrame.size.width, popoverHeight-scrollViewYOffset)];
+}
+
+- (void)updateStyle {
+ NSDictionary *images = VKPCGetImagesDictionary();
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSFont *bold = [fontManager fontWithFamily:GetSystemFontName() traits:NSUnitalicFontMask weight:9 size:13.0];
+
+ VibrantTextField *ph = [[[self customView] subviews] objectAtIndex:0];
+
+ switch (GetInterfaceStyle()) {
+ case InterfaceStyleLegacy:
+ // title
+ [_titleTextField setTextColor:[NSColor colorWithSRGBRed:0.498 green:0.51 blue:0.522 alpha:1]];
+
+ // placeholder
+ [ph setTextColor:[NSColor colorWithSRGBRed:0.612 green:0.624 blue:0.631 alpha:1]];
+ break;
+
+ case InterfaceStyleYosemite:
+ // title
+ [_titleTextFieldCell setTextColor:[NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.0 alpha:0.32]];
+
+ // placeholder
+ [ph setTextColor:[NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.0 alpha:0.2]];
+ break;
+
+ case InterfaceStyleYosemiteDark:
+ // title
+ [_titleTextField setTextColor:[NSColor colorWithSRGBRed:1.0 green:1.0 blue:1.0 alpha:0.5]];
+
+ // placeholder
+ [ph setTextColor:[NSColor colorWithSRGBRed:1.0 green:1.0 blue:1.0 alpha:0.2]];
+ break;
+ }
+
+ [_titleTextField setFont:bold];
+
+ [_titleSeparatorImageCell setImage:images[VKPCImageTitleSeparator]];
+ [_settingsButtonCell setImage:images[VKPCImageSettings]];
+ [_settingsButtonCell setAlternateImage:images[VKPCImageSettingsPressed]];
+}
+
+- (void)updateTitle:(NSString *)title {
+ if ([title isEqualToString:@""]) {
+ title = [[[NSBundle mainBundle] infoDictionary] objectForKey:kCFBundleDisplayName];
+ }
+ [_titleTextField setStringValue:title];
+}
+
+- (IBAction)menuButtonAction:(id)sender {
+ [NSMenu popUpContextMenu:_appMenu
+ withEvent:[NSApp currentEvent]
+ forView:sender];
+}
+
+//- (IBAction)systemConfigurationRequiredAction:(id)sender {
+// [[Popover shared] hidePopover];
+// [HostsHack showWindow];
+//}
+
+- (IBAction)menuItemAboutAction:(id)sender {
+ if (!aboutWindowController) {
+ aboutWindowController = [[AboutWindowController alloc] initWithWindowNibName:@"AboutWindow"];
+ }
+ [aboutWindowController showWindow:nil];
+ [aboutWindowController.window makeKeyAndOrderFront:nil];
+ [NSApp activateIgnoringOtherApps:YES];
+
+ [[Popover shared] hidePopover];
+}
+
+- (IBAction)menuItemQuitAction:(id)sender {
+ [[NSApplication sharedApplication] terminate:nil];
+}
+
+- (IBAction)menuItemShowNotificationsAction:(id)sender {
+ NSInteger newState = InvertNSState(_menuItemShowNotifications.state);
+ [_menuItemShowNotifications setState:newState];
+ [[NSUserDefaults standardUserDefaults] setBool:BoolFromNSState(newState) forKey:VKPCPreferencesShowNotifications];
+}
+
+- (IBAction)menuItemInvertAction:(id)sender {
+ NSInteger newState = InvertNSState(_menuItemInvert.state);
+ [_menuItemInvert setState:newState];
+ [[NSUserDefaults standardUserDefaults] setBool:BoolFromNSState(newState) forKey:VKPCPreferencesInvertPlaylistIcons];
+}
+
+- (IBAction)menuItemCatchAction:(id)sender {
+ NSInteger newState = InvertNSState(_menuItemCatch.state);
+ [_menuItemCatch setState:newState];
+ [[NSUserDefaults standardUserDefaults] setBool:BoolFromNSState(newState) forKey:VKPCPreferencesCatchMediaButtons];
+}
+
+- (IBAction)menuItemAutostartAction:(id)sender {
+ BOOL status = [Autostart isLaunchAtStartup];
+ [Autostart toggleLaunchAtStartup];
+ [_menuItemAutostart setState:NSStateFromBool(!status)];
+}
+
+#ifdef DEBUG
+- (IBAction)menuInjectAction:(id)sender {
+ [Controller debugInject];
+}
+
+- (IBAction)menuSendPlayAction:(id)sender {
+ [Controller debugSendPlay];
+}
+
+- (IBAction)menuJSToClipboardAction:(id)sender {
+ [Controller debugCopyJS];
+}
+
+- (IBAction)menuASToClipboardAction:(id)sender {
+ [Controller debugCopyAS];
+}
+
+- (IBAction)menuNotificationAction:(id)sender {
+ [NSTimer scheduledTimerWithTimeInterval:1.0
+ target:self
+ selector:@selector(showTestNotification)
+ userInfo:nil
+ repeats:NO];
+ [[Popover shared] hidePopover];
+}
+
+- (void)showTestNotification {
+ ShowNotification(@"Title", @"Text");
+}
+
+//- (IBAction)menuShowHHWindowAction:(id)sender {
+// [[Popover shared] hidePopover];
+// [HostsHack showWindow];
+//}
+
+- (IBAction)menuAddTracksAction:(id)sender {
+ for (int i = 0; i < 1000; i++)
+ [_playlistTableController.playlist.tracks addObject:@{
+ @"id": @"0_0",
+ @"artist": [@"Within Temptation " stringByAppendingString:[NSString stringWithFormat:@"%d", i]],
+ @"title": [@"Promise " stringByAppendingString:[NSString stringWithFormat:@"%d", i]],
+ @"duration": @"7:25",
+ @"playImage": VKPCGetImagesDictionary()[VKPCImageEmpty]
+ }];
+ [_playlistTableController playlistUpdated];
+}
+
+- (IBAction)menuRemoveTracksAction:(id)sender {
+ [_playlistTableController clearPlaylist];
+// [_playlistTableController.playlist.tracks removeAllObjects];
+// [_playlistTableController playlistUpdated];
+}
+
+- (IBAction)menuPrintDebugInfoAction:(id)sender {
+ for (int i = 0; i < 5; i++) {
+ NSLog(@"[DEBUG INFO] browserid=%d, connected=%zd", i, [Server connectedCount:i]);
+ }
+ if (_playlistTableController) {
+ NSLog(@"[DEBUG_INFO] playlist id: %zu", _playlistTableController.playlist.playlistID);
+ }
+ NSLog(@"[DEBUG_INFO] sid: %d", VKPCSessionID);
+}
+
+- (IBAction)menuSomethingAction:(id)sender {
+// for (int i = 0; i < 20; i++) {
+// [CatchMediaButtons stop];
+// [CatchMediaButtons start];
+// }
+// NSLog(@"timestamp: %ld\n", GetTimestamp());
+// NSLog(@"another timestamp: %lf\n", [[NSDate date] timeIntervalSince1970]);
+// / NSLog(@"UUID: %@", [[NSUserDefaults standardUserDefaults] stringForKey:VKPCPreferencesUUID]);
+ [Statistics initialize];
+}
+#endif
+
+- (IBAction)menuItemBrowserAction:(id)sender {
+ NSMenuItem *item = (NSMenuItem *)sender;
+ NSInteger index = [[_browserMenu itemArray] indexOfObject:item];
+
+ for (int i = 0; i < BrowsersCount; i++) {
+ if (i != index) {
+ [(NSMenuItem *)[_browserMenu itemArray][i] setState:NSOffState];
+ } else {
+ [item setState:NSOnState];
+ }
+ }
+
+ [[NSUserDefaults standardUserDefaults] setInteger:index forKey:VKPCPreferencesBrowser];
+}
+
+- (IBAction)menuItemDownloadExtensionsAction:(id)sender {
+ [[Popover shared] hidePopover];
+ [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://ch1p.com/vkpc/#extensions"]];
+}
+
+- (IBAction)menuItemCheckForUpdatesAction:(id)sender {
+ [[Popover shared] hidePopover];
+ [_sparkleUpdater checkForUpdates:sender];
+}
+
+- (IBAction)useExtensionModeAction:(id)sender {
+ BOOL use = BoolFromNSState(((NSMenuItem *)sender).state);
+ [_useExtensionMode setState:NSStateFromBool(!use)];
+ [[NSUserDefaults standardUserDefaults] setBool:BoolFromNSState(!use) forKey:VKPCPreferencesUseExtensionMode];
+ [self useExtensionModeUpdated];
+}
+
+- (void)useExtensionModeUpdated {
+ BOOL use = BoolFromNSState(_useExtensionMode.state);
+ [_downloadExtensionsMenuItem setTitle:( use ? @"Download extensions" : @"Extensions for Firefox and Opera" )];
+}
+
+//#if !IS_PRODUCTION
+//
+//- (IBAction)onSettingsItemTestAddTracksClick:(id)sender {
+// [playlistTableController testAddTracks];
+//}
+//
+//- (IBAction)onSettingsItemTestRemoveAllTracksClick:(id)sender {
+// [playlistTableController testRemoveAllTracks];
+//}
+//
+//- (IBAction)onSettingsItemTestResizePopoverClick:(id)sender {
+// NSSize popoverSize = [[self statusItemPopup] getSize];
+// int add = 100;
+//
+// [[self statusItemPopup] setSize:NSMakeSize(popoverSize.width, popoverSize.height+add) animate:YES];
+//}
+//
+//- (IBAction)onSettingsItemTestPrintDebugInfoClick:(id)sender {
+// NSRect rect = [[self _view] frame], scrollRect = [[self scrollView] frame];
+// NSLog(@"[view] x: %f, y: %f, width: %f, height: %f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+// NSLog(@"[scrollView] x: %f, y: %f, width: %f, height: %f", scrollRect.origin.x, scrollRect.origin.y, scrollRect.size.width, scrollRect.size.height);
+//}
+//
+//# endif
+
+- (void)popoverDidShow {
+ [_scrollView setHidden:NO];
+ if (setHeightOnShow != -1) {
+ [self doResizeWithContentHeight:setHeightOnShow animate:NO];
+ setHeightOnShow = -1;
+ }
+}
+
+- (void)popoverDidHide {
+ [_scrollView setHidden:YES];
+}
+
+- (void)darkModeChanged:(NSNotification *)notification {
+ [self updateStyle];
+
+ for (int i = 0; i < _playlistTableView.numberOfRows; i++) {
+ [[_playlistTableController getCellViewForIndex:i] updateStyle];
+ }
+}
+
+- (void)invertPrefChanged {
+ Playlist *playlist = _playlistTableController.playlist;
+ PlayingTrackStatus playing = playlist.playing;
+ NSInteger index = playing.index;
+
+ if (index < _playlistTableView.numberOfRows) {
+ [[_playlistTableController getCellViewForIndex:index] drawMode];
+ }
+}
+
+// KVO
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+ if ([keyPath isEqualToString:VKPCPreferencesInvertPlaylistIcons]) {
+ NSNumber *new = change[NSKeyValueChangeKindKey];
+ if ([new integerValue] == NSKeyValueChangeSetting) {
+ [self invertPrefChanged];
+ }
+ }
+}
+
+@end