From c974751621f16965e803c0ef9e2baf0f6f380da5 Mon Sep 17 00:00:00 2001 From: Duncan Robertson Date: Tue, 4 Feb 2014 13:02:00 +0000 Subject: [PATCH 1/5] work in progress --- app/_views/upcoming_view.rb | 81 ++++++++++++++++++++++++++ app/controllers/upcoming_controller.rb | 29 +++++++++ app/menu.rb | 10 ++++ 3 files changed, 120 insertions(+) create mode 100644 app/_views/upcoming_view.rb create mode 100644 app/controllers/upcoming_controller.rb diff --git a/app/_views/upcoming_view.rb b/app/_views/upcoming_view.rb new file mode 100644 index 0000000..59f92b7 --- /dev/null +++ b/app/_views/upcoming_view.rb @@ -0,0 +1,81 @@ +class UpcomingView < NSView + + attr_accessor :table + + def initWithFrame(frame) + super(frame).tap do |cell| + cell.translatesAutoresizingMaskIntoConstraints = false + + @table ||= draw_table + + views_dict = { + "table" => @table + } + + metrics_dict = { + "h_spacing" => 5, + "h_padding" => 10, + "v_padding" => 10 + } + + views_dict.each do |key, view| + cell.addSubview(view) + end + + constraints = [] + constraints += NSLayoutConstraint.constraintsWithVisualFormat( + "V:|[table]|", + options:NSLayoutFormatAlignAllLeft, + metrics:metrics_dict, + views:views_dict + ) + constraints += NSLayoutConstraint.constraintsWithVisualFormat( + "H:|[table]|", + options:0, + metrics:metrics_dict, + views:views_dict + ) + cell.addConstraints(constraints) + end + end + + def refresh(jukebox) + @jukebox = jukebox + update_data! + end + + def track + @jukebox.track unless @jukebox.nil? + end + + def rating + @jukebox.rating unless @jukebox.nil? + end + + private + + def valid_jb_data?(key) + @jukebox.whats_changed.include?(key) + end + + def should_update? + valid_jb_data?(:track) || valid_jb_data?(:rating) + end + + def update_data! + if @jukebox && should_update? + update_table + end + + invalidateIntrinsicContentSize + setNeedsDisplay(true) + end + + def draw_table + NSTableView.new + end + + def update_table + end + +end \ No newline at end of file diff --git a/app/controllers/upcoming_controller.rb b/app/controllers/upcoming_controller.rb new file mode 100644 index 0000000..f7ff00a --- /dev/null +++ b/app/controllers/upcoming_controller.rb @@ -0,0 +1,29 @@ +class UpcomingController < NSViewController + + def init + super.tap do |c| + c.build_view + + @update_observer = App.notification_center.observe JB_UPDATED do |n| + view.refresh(n.userInfo[:jukebox]) + end + end + end + + def build_view + @main_view = UpcomingView.alloc.initWithFrame([[0, 0], [50, 50]]) + @main_view.table.setDelegate(self) + @main_view.table.setDataSource(self) + self.setView(@main_view) + end + + + def numberOfRowsInTableView + 3 + end + + def tableView(tableView, objectValueForTableColumn:objVal, row:row) + 'Hello' + end + +end \ No newline at end of file diff --git a/app/menu.rb b/app/menu.rb index fb6d271..54d4782 100644 --- a/app/menu.rb +++ b/app/menu.rb @@ -6,6 +6,7 @@ def setup_build_menu @menu.initWithTitle App.name @menu.setMinimumWidth(DEFAULT_MENU_WIDTH) @jukebox_menu ||= NowplayingController.new + @upcoming_tracks ||= UpcomingController.new build_menu(@menu) @@ -35,6 +36,7 @@ def build_menu(menu) if jukebox_available? build_now_playing(menu) + build_upcoming_tracks(menu) build_console_status(menu) add_seperator_for(menu) end @@ -103,6 +105,14 @@ def build_now_playing(menu) add_seperator_for(menu) end + def build_upcoming_tracks(menu) + jbmi = NSMenuItem.new + jbmi.tag = MENU_NOWPLAYING + jbmi.view = @upcoming_tracks.view + menu.addItem(jbmi) + add_seperator_for(menu) + end + def build_secret_refresh NSMenuItem.new.tap do |mi| mi.title = 'Force Refresh!' From 725d2b056d73dd87ef656f41f9ed4b2043658342 Mon Sep 17 00:00:00 2001 From: Duncan Robertson Date: Tue, 19 Jan 2016 11:01:56 +0000 Subject: [PATCH 2/5] Add upcoming tracks to status bar --- Gemfile | 2 +- Gemfile.lock | 6 +- Rakefile | 1 + app/_views/upcoming_table_view.rb | 24 ++++++ app/_views/upcoming_view.rb | 81 -------------------- app/controllers/upcoming_controller.rb | 100 ++++++++++++++++++++++--- 6 files changed, 119 insertions(+), 95 deletions(-) create mode 100644 app/_views/upcoming_table_view.rb delete mode 100644 app/_views/upcoming_view.rb diff --git a/Gemfile b/Gemfile index 090142a..c78769e 100644 --- a/Gemfile +++ b/Gemfile @@ -9,5 +9,5 @@ gem 'sugarcube', :require => [ 'sugarcube-attributedstring', ] gem "ib" -#gem "kyan_jukebox_websocket_lib", :path => "/Users/duncan/_dev/kyan/gems/kyan_jukebox_websocket_lib" +#gem "kyan_jukebox", :path => "/Users/duncan/_dev/kyan/gems/kyan_jukebox_websocket_lib" gem "kyan_jukebox", :git => 'git@github.com:kyan/kyan_jukebox_websocket_lib.git' diff --git a/Gemfile.lock b/Gemfile.lock index bd5e20b..8fb615a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,8 +1,8 @@ GIT remote: git@github.com:kyan/kyan_jukebox_websocket_lib.git - revision: 60178464e15c2465357326aa40906c1e71377de5 + revision: 8bfe8b70b4ed6fefb491591d9e62279c262ade7d specs: - kyan_jukebox (0.2.0) + kyan_jukebox (0.2.3) GEM remote: https://rubygems.org/ @@ -85,4 +85,4 @@ DEPENDENCIES sugarcube BUNDLED WITH - 1.10.6 + 1.11.2 diff --git a/Rakefile b/Rakefile index 0b885be..feb5d51 100644 --- a/Rakefile +++ b/Rakefile @@ -17,6 +17,7 @@ Motion::Project::App.setup do |app| app.info_plist['NSUIElement'] = 1 app.info_plist['NSHumanReadableCopyright'] = 'Copyright © 2016, Kyan Ltd' + app.info_plist['NSAppTransportSecurity'] = { 'NSAllowsArbitraryLoads' => true } app.pods do pod 'SocketRocket' diff --git a/app/_views/upcoming_table_view.rb b/app/_views/upcoming_table_view.rb new file mode 100644 index 0000000..9f44f82 --- /dev/null +++ b/app/_views/upcoming_table_view.rb @@ -0,0 +1,24 @@ +class UpcomingTableView < NSTableView + + def init + super.tap do |v| + v.translatesAutoresizingMaskIntoConstraints = false + + col2 = NSTableColumn.alloc.initWithIdentifier "col2" + col2.setWidth 20 + col2.identifier = :thumb + v.addTableColumn col2 + + col3 = NSTableColumn.alloc.initWithIdentifier "col3" + col3.setWidth 220 + col3.identifier = :title + v.addTableColumn col3 + + col4 = NSTableColumn.alloc.initWithIdentifier "col4" + col4.setWidth 40 + col4.identifier = :duration + v.addTableColumn col4 + end + end + +end diff --git a/app/_views/upcoming_view.rb b/app/_views/upcoming_view.rb deleted file mode 100644 index 59f92b7..0000000 --- a/app/_views/upcoming_view.rb +++ /dev/null @@ -1,81 +0,0 @@ -class UpcomingView < NSView - - attr_accessor :table - - def initWithFrame(frame) - super(frame).tap do |cell| - cell.translatesAutoresizingMaskIntoConstraints = false - - @table ||= draw_table - - views_dict = { - "table" => @table - } - - metrics_dict = { - "h_spacing" => 5, - "h_padding" => 10, - "v_padding" => 10 - } - - views_dict.each do |key, view| - cell.addSubview(view) - end - - constraints = [] - constraints += NSLayoutConstraint.constraintsWithVisualFormat( - "V:|[table]|", - options:NSLayoutFormatAlignAllLeft, - metrics:metrics_dict, - views:views_dict - ) - constraints += NSLayoutConstraint.constraintsWithVisualFormat( - "H:|[table]|", - options:0, - metrics:metrics_dict, - views:views_dict - ) - cell.addConstraints(constraints) - end - end - - def refresh(jukebox) - @jukebox = jukebox - update_data! - end - - def track - @jukebox.track unless @jukebox.nil? - end - - def rating - @jukebox.rating unless @jukebox.nil? - end - - private - - def valid_jb_data?(key) - @jukebox.whats_changed.include?(key) - end - - def should_update? - valid_jb_data?(:track) || valid_jb_data?(:rating) - end - - def update_data! - if @jukebox && should_update? - update_table - end - - invalidateIntrinsicContentSize - setNeedsDisplay(true) - end - - def draw_table - NSTableView.new - end - - def update_table - end - -end \ No newline at end of file diff --git a/app/controllers/upcoming_controller.rb b/app/controllers/upcoming_controller.rb index f7ff00a..52166d2 100644 --- a/app/controllers/upcoming_controller.rb +++ b/app/controllers/upcoming_controller.rb @@ -2,28 +2,108 @@ class UpcomingController < NSViewController def init super.tap do |c| + c.init_data c.build_view @update_observer = App.notification_center.observe JB_UPDATED do |n| - view.refresh(n.userInfo[:jukebox]) + refresh(n.userInfo[:jukebox]) end end end + def refresh(jukebox) + @jukebox = jukebox + refresh_tracks + @table_view.reloadData + end + + def init_data + @upcoming_tracks = [] + end + def build_view - @main_view = UpcomingView.alloc.initWithFrame([[0, 0], [50, 50]]) - @main_view.table.setDelegate(self) - @main_view.table.setDataSource(self) - self.setView(@main_view) + @table_view = UpcomingTableView.alloc.init + @table_view.setBoundsOrigin([-10,0]); + @table_view.setBoundsSize([@table_view.bounds.size.width+20, @table_view.bounds.size.height]); + @table_view.delegate = self + @table_view.dataSource = self + self.setView(@table_view) + end + + def numberOfRowsInTableView(table_view) + @upcoming_tracks.count + end + + def tableView(table_view, objectValueForTableColumn:table_column, row:row) + case table_column.identifier.to_sym + when :thumb + if @upcoming_tracks[row].artwork_url.nil? + NSImage.imageNamed("missing_artwork.png") + else + url = NSURL.URLWithString(@upcoming_tracks[row].artwork_url) + NSImage.alloc.initWithContentsOfURL(url) + end + when :title + str = "#{@upcoming_tracks[row].heading} (#{@upcoming_tracks[row].added_by})" + paragraph = NSMutableParagraphStyle.new + paragraph.setLineBreakMode(NSLineBreakByTruncatingTail) + + str.attrd({ + 'NSParagraphStyle' => paragraph + }) + when :duration + @upcoming_tracks[row].eta + end + end + + def tableView(table_view, heightOfRow:row) + 20 end + def tableView(table_view, viewForTableColumn:table_column, row:row) + tview = table_view.makeViewWithIdentifier(table_column.identifier, owner:self) + + case table_column.identifier.to_sym + when :thumb + tview = NSImageView.new.tap do |v| + v.setTranslatesAutoresizingMaskIntoConstraints(false) + v.setEditable(false) + v.setImageScaling(NSImageScaleAxesIndependently) + v.identifier = 'thumbid' + end + when :title + tview = NSTextField.new.tap do |v| + v.frame = CGRectZero + v.font = NSFont.systemFontOfSize(12.0) + v.setEditable(false) + v.setBezeled(false) + v.setDrawsBackground(false) + v.setSelectable(false) + v.identifier = 'titleid' + end + else + tview = NSTextField.new.tap do |v| + v.frame = CGRectZero + v.setEditable(false) + v.setBezeled(false) + v.setAlignment(NSRightTextAlignment) + v.setDrawsBackground(false) + v.setSelectable(false) + v.identifier = 'defaultid' + end + end - def numberOfRowsInTableView - 3 + tview end - def tableView(tableView, objectValueForTableColumn:objVal, row:row) - 'Hello' + private + + def refresh_tracks + @upcoming_tracks = @jukebox.playlist.upcoming_tracks(current_track)[0...5] end -end \ No newline at end of file + def current_track + return @jukebox.track.file if @jukebox.last_change?(:track) + nil + end +end From 13e727088a0cb7aa7afe6b9be1817fc22076bf16 Mon Sep 17 00:00:00 2001 From: Duncan Robertson Date: Tue, 19 Jan 2016 11:02:21 +0000 Subject: [PATCH 3/5] Make 'reconnect to jukebox' visable at all times --- app/menu.rb | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/app/menu.rb b/app/menu.rb index 54d4782..170d430 100644 --- a/app/menu.rb +++ b/app/menu.rb @@ -23,17 +23,6 @@ def build_menu(menu) menu = setup_build_menu if menu.nil? menu.removeAllItems - flags = (NSEvent.modifierFlags & NSDeviceIndependentModifierFlagsMask) - - # If you hold the ALT key and display the - # menu it will show an extra item that lets - # you refersh your connection to the jukebox - # - if flags == NSAlternateKeyMask - menu.addItem(build_secret_refresh) - add_seperator_for(menu) - end - if jukebox_available? build_now_playing(menu) build_upcoming_tracks(menu) @@ -45,7 +34,9 @@ def build_menu(menu) m = NSMenuItem.new m.title = data.first m.tag = i - m.setImage( NSImage.imageNamed(data.first.downcase) ) + icon_img = NSImage.imageNamed(data.first.downcase) + icon_img.template = true + m.image = icon_img m.action = 'open_link:' @menu.addItem m end @@ -78,6 +69,13 @@ def build_submenu mi.tag = MENU_ABOUT sub_menu.addItem mi + mi = NSMenuItem.new + mi.title = 'Force reconnect to Jukebox!' + mi.action = 'force_reconnect_to_websocket_server' + mi.tag = MENU_FORCE_REFRESH + mi.toolTip = RECONNECT_TXT + sub_menu.addItem mi + add_seperator_for(sub_menu) mi = NSMenuItem.new @@ -113,16 +111,6 @@ def build_upcoming_tracks(menu) add_seperator_for(menu) end - def build_secret_refresh - NSMenuItem.new.tap do |mi| - mi.title = 'Force Refresh!' - mi.action = 'force_reconnect_to_websocket_server' - mi.tag = MENU_FORCE_REFRESH - mi.setKeyEquivalent("r") - mi.setKeyEquivalentModifierMask(NSCommandKeyMask) - end - end - def build_console_status(menu) butt = NSMenuItem.new butt.tag = MENU_CONSOLE_BUTT @@ -154,7 +142,7 @@ def add_seperator_for(menu) def links [ - ["Timesheet" , "https://gapps.harvestapp.com/gapp_company?domain=kyanmedia.com"], + ["Timesheet" , "https://id.getharvest.com/accounts"], ["Pivotal" , "https://www.pivotaltracker.com/google_domain_openid/redirect_for_auth?domain=kyanmedia.com"], ["Support" , "https://kyan.sirportly.com"], ["Holiday" , "https://app.timetastic.co.uk"], From 849cb2580aaef752779c39ce8881cc8a34142a99 Mon Sep 17 00:00:00 2001 From: Duncan Robertson Date: Tue, 19 Jan 2016 11:03:09 +0000 Subject: [PATCH 4/5] Make fonts and icons appear correct when 'dark status bar' mode --- app/_views/nowplaying_view.rb | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/app/_views/nowplaying_view.rb b/app/_views/nowplaying_view.rb index 41bfdc4..7bef0db 100644 --- a/app/_views/nowplaying_view.rb +++ b/app/_views/nowplaying_view.rb @@ -121,6 +121,7 @@ def update_data! def draw_title_box NSTextField.new.tap do |v| + v.setFont(NSFont.systemFontOfSize(12.0)) v.setEditable(false) v.setBezeled(false) v.setDrawsBackground(false) @@ -130,12 +131,12 @@ def draw_title_box NSLayoutPriorityDefaultLow, forOrientation:NSLayoutConstraintOrientationHorizontal ) - v.cell.setBackgroundStyle(NSBackgroundStyleRaised) end end def draw_artist_box NSTextField.new.tap do |v| + v.setFont(NSFont.systemFontOfSize(10.0)) v.setEditable(false) v.setBezeled(false) v.setDrawsBackground(false) @@ -145,12 +146,12 @@ def draw_artist_box NSLayoutPriorityDefaultLow, forOrientation:NSLayoutConstraintOrientationHorizontal ) - v.cell.setBackgroundStyle(NSBackgroundStyleRaised) end end def draw_album_box NSTextField.new.tap do |v| + v.setFont(NSFont.systemFontOfSize(9.0)) v.setEditable(false) v.setBezeled(false) v.setDrawsBackground(false) @@ -160,7 +161,6 @@ def draw_album_box NSLayoutPriorityDefaultLow, forOrientation:NSLayoutConstraintOrientationHorizontal ) - v.cell.setBackgroundStyle(NSBackgroundStyleRaised) end end @@ -170,6 +170,7 @@ def draw_image_box def draw_addedby_box NSTextField.new.tap do |v| + v.setFont(NSFont.systemFontOfSize(8.0)) v.setEditable(false) v.setBezeled(false) v.setDrawsBackground(false) @@ -179,7 +180,6 @@ def draw_addedby_box NSLayoutPriorityDefaultLow, forOrientation:NSLayoutConstraintOrientationHorizontal ) - v.cell.setBackgroundStyle(NSBackgroundStyleRaised) end end @@ -188,8 +188,6 @@ def update_title paragraph.setLineBreakMode(NSLineBreakByTruncatingTail) txt = track.title.attrd({ - 'NSFont' => NSFont.systemFontOfSize(12.0), - 'NSColor' => NSColor.blackColor, 'NSParagraphStyle' => paragraph }) unless track.title.nil? @title.setAttributedStringValue(txt) @@ -201,8 +199,6 @@ def update_artist paragraph.setLineBreakMode(NSLineBreakByTruncatingTail) txt = track.artist.attrd({ - 'NSFont' => NSFont.systemFontOfSize(10.0), - 'NSColor' => NSColor.blackColor, 'NSParagraphStyle' => paragraph }) unless track.artist.nil? @artist.setAttributedStringValue(txt) @@ -215,8 +211,6 @@ def update_album paragraph.setLineBreakMode(NSLineBreakByTruncatingTail) txt = track.album.attrd({ - 'NSFont' => NSFont.systemFontOfSize(9.0), - 'NSColor' => NSColor.blackColor, 'NSParagraphStyle' => paragraph }) unless track.album.nil? @album.setAttributedStringValue(txt) @@ -229,8 +223,6 @@ def update_addedby paragraph.setLineBreakMode(NSLineBreakByTruncatingTail) txt = "#{CHOSEN_BY_TXT} #{track.added_by}".attrd({ - 'NSFont' => NSFont.systemFontOfSize(8.0), - 'NSColor' => NSColor.blackColor, 'NSParagraphStyle' => paragraph }) unless track.added_by.nil? @addedby.setAttributedStringValue(txt) From 21d6a384db0c93a4f71483a00334aead98d7fd67 Mon Sep 17 00:00:00 2001 From: Duncan Robertson Date: Tue, 19 Jan 2016 11:03:24 +0000 Subject: [PATCH 5/5] tooltip text for menu --- app/config/constants.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/config/constants.rb b/app/config/constants.rb index a5ad8ce..657659d 100644 --- a/app/config/constants.rb +++ b/app/config/constants.rb @@ -3,6 +3,8 @@ JUKEBOX_URL = "http://#{WEBSOCKET_HOST}" VOTE_URL = "#{JUKEBOX_URL}/external?" +RECONNECT_TXT = 'If you have any issues with the now playing information not showing, this should fix it.' + DEFAULT_MENU_WIDTH=250.0 MENU_NOWPLAYING=111 @@ -43,4 +45,4 @@ SB_ICON_ACTIVE = "k_logo_col_18x18" SB_ICON_INACTIVE = "k_logo_bw_18x18" -GLOBAL_H_PADDING = 10 \ No newline at end of file +GLOBAL_H_PADDING = 10