Add now playing item

This commit is contained in:
Shadowfacts 2019-07-13 22:22:05 -04:00
parent 88e8d606b4
commit 4b17e0d361
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
9 changed files with 198 additions and 63 deletions

View File

@ -14,8 +14,8 @@
D6B35B4E22DA479E00F262A2 /* TouchBarItemIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B35B4D22DA479E00F262A2 /* TouchBarItemIdentifiers.swift */; }; D6B35B4E22DA479E00F262A2 /* TouchBarItemIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B35B4D22DA479E00F262A2 /* TouchBarItemIdentifiers.swift */; };
D6B35B5122DA4A2A00F262A2 /* DFRFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B35B5022DA4A2A00F262A2 /* DFRFoundation.framework */; }; D6B35B5122DA4A2A00F262A2 /* DFRFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B35B5022DA4A2A00F262A2 /* DFRFoundation.framework */; };
D6B35B5522DA64AD00F262A2 /* RootTouchBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B35B5422DA64AD00F262A2 /* RootTouchBarController.swift */; }; D6B35B5522DA64AD00F262A2 /* RootTouchBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B35B5422DA64AD00F262A2 /* RootTouchBarController.swift */; };
D6B35B5A22DA66A400F262A2 /* TouchBarWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B35B5922DA66A400F262A2 /* TouchBarWidget.swift */; }; D6B35B6222DA6B2100F262A2 /* NowPlayingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B35B6122DA6B2100F262A2 /* NowPlayingItem.swift */; };
D6B35B5E22DA687E00F262A2 /* NowPlayingWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B35B5D22DA687E00F262A2 /* NowPlayingWidget.swift */; }; D6B35B6522DA6ECC00F262A2 /* MediaRemote.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B35B6422DA6ECC00F262A2 /* MediaRemote.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -31,8 +31,9 @@
D6B35B4D22DA479E00F262A2 /* TouchBarItemIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchBarItemIdentifiers.swift; sourceTree = "<group>"; }; D6B35B4D22DA479E00F262A2 /* TouchBarItemIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchBarItemIdentifiers.swift; sourceTree = "<group>"; };
D6B35B5022DA4A2A00F262A2 /* DFRFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DFRFoundation.framework; path = ../../../../System/Library/PrivateFrameworks/DFRFoundation.framework; sourceTree = "<group>"; }; D6B35B5022DA4A2A00F262A2 /* DFRFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DFRFoundation.framework; path = ../../../../System/Library/PrivateFrameworks/DFRFoundation.framework; sourceTree = "<group>"; };
D6B35B5422DA64AD00F262A2 /* RootTouchBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootTouchBarController.swift; sourceTree = "<group>"; }; D6B35B5422DA64AD00F262A2 /* RootTouchBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootTouchBarController.swift; sourceTree = "<group>"; };
D6B35B5922DA66A400F262A2 /* TouchBarWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchBarWidget.swift; sourceTree = "<group>"; }; D6B35B6122DA6B2100F262A2 /* NowPlayingItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingItem.swift; sourceTree = "<group>"; };
D6B35B5D22DA687E00F262A2 /* NowPlayingWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingWidget.swift; sourceTree = "<group>"; }; D6B35B6322DA6E5700F262A2 /* MRMediaRemote.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MRMediaRemote.h; sourceTree = "<group>"; };
D6B35B6422DA6ECC00F262A2 /* MediaRemote.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaRemote.framework; path = ../../../../System/Library/PrivateFrameworks/MediaRemote.framework; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -41,6 +42,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D6B35B5122DA4A2A00F262A2 /* DFRFoundation.framework in Frameworks */, D6B35B5122DA4A2A00F262A2 /* DFRFoundation.framework in Frameworks */,
D6B35B6522DA6ECC00F262A2 /* MediaRemote.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -67,16 +69,16 @@
D6B35B3722DA1B3C00F262A2 /* Underbar */ = { D6B35B3722DA1B3C00F262A2 /* Underbar */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D6B35B4A22DA1C8400F262A2 /* Underbar-Bridging-Header.h */,
D6B35B3822DA1B3C00F262A2 /* AppDelegate.swift */, D6B35B3822DA1B3C00F262A2 /* AppDelegate.swift */,
D6B35B4D22DA479E00F262A2 /* TouchBarItemIdentifiers.swift */, D6B35B4D22DA479E00F262A2 /* TouchBarItemIdentifiers.swift */,
D6B35B5F22DA6AD500F262A2 /* Private */,
D6B35B5722DA669000F262A2 /* Controllers */, D6B35B5722DA669000F262A2 /* Controllers */,
D6B35B5822DA669400F262A2 /* Widgets */, D6B35B6022DA6B0400F262A2 /* Items */,
D6B35B3C22DA1B3C00F262A2 /* Assets.xcassets */, D6B35B3C22DA1B3C00F262A2 /* Assets.xcassets */,
D6B35B3E22DA1B3C00F262A2 /* Main.storyboard */, D6B35B3E22DA1B3C00F262A2 /* Main.storyboard */,
D6B35B4122DA1B3C00F262A2 /* Info.plist */, D6B35B4122DA1B3C00F262A2 /* Info.plist */,
D6B35B4222DA1B3C00F262A2 /* Underbar.entitlements */, D6B35B4222DA1B3C00F262A2 /* Underbar.entitlements */,
D6B35B4822DA1B8D00F262A2 /* NSTouchBar.h */,
D6B35B4A22DA1C8400F262A2 /* Underbar-Bridging-Header.h */,
); );
path = Underbar; path = Underbar;
sourceTree = "<group>"; sourceTree = "<group>";
@ -84,6 +86,7 @@
D6B35B4F22DA4A2A00F262A2 /* Frameworks */ = { D6B35B4F22DA4A2A00F262A2 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D6B35B6422DA6ECC00F262A2 /* MediaRemote.framework */,
D6B35B5022DA4A2A00F262A2 /* DFRFoundation.framework */, D6B35B5022DA4A2A00F262A2 /* DFRFoundation.framework */,
); );
name = Frameworks; name = Frameworks;
@ -98,13 +101,21 @@
path = Controllers; path = Controllers;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D6B35B5822DA669400F262A2 /* Widgets */ = { D6B35B5F22DA6AD500F262A2 /* Private */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D6B35B5922DA66A400F262A2 /* TouchBarWidget.swift */, D6B35B4822DA1B8D00F262A2 /* NSTouchBar.h */,
D6B35B5D22DA687E00F262A2 /* NowPlayingWidget.swift */, D6B35B6322DA6E5700F262A2 /* MRMediaRemote.h */,
); );
path = Widgets; path = Private;
sourceTree = "<group>";
};
D6B35B6022DA6B0400F262A2 /* Items */ = {
isa = PBXGroup;
children = (
D6B35B6122DA6B2100F262A2 /* NowPlayingItem.swift */,
);
path = Items;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
/* End PBXGroup section */ /* End PBXGroup section */
@ -177,10 +188,9 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D6B35B5A22DA66A400F262A2 /* TouchBarWidget.swift in Sources */,
D6B35B4E22DA479E00F262A2 /* TouchBarItemIdentifiers.swift in Sources */, D6B35B4E22DA479E00F262A2 /* TouchBarItemIdentifiers.swift in Sources */,
D6B35B4C22DA466600F262A2 /* TouchBarController.swift in Sources */, D6B35B4C22DA466600F262A2 /* TouchBarController.swift in Sources */,
D6B35B5E22DA687E00F262A2 /* NowPlayingWidget.swift in Sources */, D6B35B6222DA6B2100F262A2 /* NowPlayingItem.swift in Sources */,
D6B35B3922DA1B3C00F262A2 /* AppDelegate.swift in Sources */, D6B35B3922DA1B3C00F262A2 /* AppDelegate.swift in Sources */,
D6B35B5522DA64AD00F262A2 /* RootTouchBarController.swift in Sources */, D6B35B5522DA64AD00F262A2 /* RootTouchBarController.swift in Sources */,
); );

View File

@ -10,15 +10,11 @@ import Cocoa
class RootTouchBarController: TouchBarController { class RootTouchBarController: TouchBarController {
let nowPlaying = NowPlayingWidget() let nowPlaying = NowPlayingItem(identifier: .nowPlaying)
override init() { override init() {
super.init() super.init()
widgets = [
nowPlaying
]
touchBar.defaultItemIdentifiers = [ touchBar.defaultItemIdentifiers = [
.closeUnderbar, .closeUnderbar,
.flexibleSpace, .flexibleSpace,
@ -31,7 +27,7 @@ class RootTouchBarController: TouchBarController {
case .closeUnderbar: case .closeUnderbar:
return createCloseItem() return createCloseItem()
case .nowPlaying: case .nowPlaying:
return nowPlaying.item return nowPlaying
default: default:
return super.touchBar(touchBar, makeItemForIdentifier: identifier) return super.touchBar(touchBar, makeItemForIdentifier: identifier)
} }

View File

@ -11,8 +11,6 @@ import Cocoa
class TouchBarController: NSObject, NSTouchBarDelegate { class TouchBarController: NSObject, NSTouchBarDelegate {
let touchBar = NSTouchBar() let touchBar = NSTouchBar()
var widgets: [TouchBarWidget] = []
var isVisible = false var isVisible = false
override init() { override init() {

View File

@ -0,0 +1,127 @@
//
// NowPlayingItem.swift
// Underbar
//
// Created by Shadowfacts on 7/13/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import Cocoa
import MediaToolbox
class NowPlayingItem: NSCustomTouchBarItem {
var nowPlayingTitle: String?
var nowPlayingArtist: String?
var nowPlayingAlbum: String?
var nowPlayingArtwork: Data?
var button: NSButton!
var lastPressTime: Date? = nil
var multiPressCount: Int = 0
var multiPressWorkItem: DispatchWorkItem? = nil
override init(identifier: NSTouchBarItem.Identifier) {
super.init(identifier: identifier)
button = NSButton(title: "Test\nline 2", target: self, action: #selector(buttonPressed))
button.alignment = .left
button.widthAnchor.constraint(equalToConstant: 200).isActive = true
view = button
MRMediaRemoteRegisterForNowPlayingNotifications(.global(qos: .utility))
registerForNotifications()
updateMediaInfo()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func registerForNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .init(kMRMediaRemoteNowPlayingApplicationClientStateDidChange), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .mrNowPlayingPlaybackQueueChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .mrNowPlayingPlaybackQueueChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .mrMediaRemoteNowPlayingApplicationIsPlayingDidChange, object: nil)
}
@objc func updateMediaInfo() {
MRMediaRemoteGetNowPlayingInfo(.main) { [weak self] (info) in
guard let self = self, let info = info else { return }
self.nowPlayingTitle = info[kMRMediaRemoteNowPlayingInfoTitle] as? String
self.nowPlayingArtist = info[kMRMediaRemoteNowPlayingInfoArtist] as? String
self.nowPlayingAlbum = info[kMRMediaRemoteNowPlayingInfoAlbum] as? String
self.nowPlayingArtwork = info[kMRMediaRemoteNowPlayingInfoArtworkData] as? Data
self.updateButtonTitle()
self.updateButtonImage()
}
}
func updateButtonTitle() {
let attributedStr = NSMutableAttributedString()
let line1 = NSAttributedString(string: nowPlayingTitle ?? "Unknown")
attributedStr.append(line1)
attributedStr.setAttributes([.font: NSFont.systemFont(ofSize: 12)], range: NSRange(location: 0, length: line1.length))
attributedStr.append(NSAttributedString(string: "\n"))
let line2 = NSAttributedString(string: (nowPlayingArtist ?? "Unknown") + " | " + (nowPlayingAlbum ?? "Unknown"))
attributedStr.append(line2)
attributedStr.setAttributes([.font: NSFont.systemFont(ofSize: 10)], range: NSRange(location: line1.length + 1, length: line2.length))
button.attributedTitle = attributedStr
}
func updateButtonImage() {
if let data = nowPlayingArtwork,
let image = NSImage(data: data) {
button.image = image
button.imagePosition = .imageLeft
} else {
button.image = nil
}
}
@objc func buttonPressed() {
if let lastPressTime = lastPressTime,
lastPressTime.timeIntervalSinceNow < 0.2 {
multiPressCount += 1
multiPressWorkItem?.cancel()
} else {
self.lastPressTime = Date()
multiPressCount = 1
}
multiPressWorkItem = DispatchWorkItem {
self.handleMultiPress(presses: self.multiPressCount)
self.lastPressTime = nil
self.multiPressCount = 0
self.multiPressWorkItem = nil
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: multiPressWorkItem!)
}
func handleMultiPress(presses: Int) {
switch presses {
case 1:
MRMediaRemoteSendCommand(kMRTogglePlayPause, nil)
case 2:
MRMediaRemoteSendCommand(kMRNextTrack, nil)
case 3:
MRMediaRemoteSendCommand(kMRPreviousTrack, nil)
default:
break
}
}
}

View File

@ -0,0 +1,43 @@
//
// MRMediaRemote.h
// Underbar
//
// Created by Shadowfacts on 7/13/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
// Copied from https://github.com/pigigaldi/Pock/blob/852679a4882d0e9c5b3d8473eb9b9fbf7bef837f/Pock/Private/MRMediaRemote.h
typedef void (^MRMediaRemoteGetNowPlayingInfoBlock)(NSDictionary *info);
typedef void (^MRMediaRemoteGetNowPlayingClientBlock)(id clientObj);
typedef void (^MRMediaRemoteGetNowPlayingApplicationIsPlayingBlock)(BOOL playing);
extern void MRMediaRemoteRegisterForNowPlayingNotifications(dispatch_queue_t queue);
extern void MRMediaRemoteGetNowPlayingClient(dispatch_queue_t queue, MRMediaRemoteGetNowPlayingClientBlock block);
extern void MRMediaRemoteGetNowPlayingClients(dispatch_queue_t queue, MRMediaRemoteGetNowPlayingClientBlock block);
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t queue, MRMediaRemoteGetNowPlayingInfoBlock block);
extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, MRMediaRemoteGetNowPlayingApplicationIsPlayingBlock block);
extern NSString *MRNowPlayingClientGetBundleIdentifier(id clientObj);
extern NSString *MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj);
extern NSString *kMRMediaRemoteNowPlayingApplicationIsPlayingDidChangeNotification;
extern NSString *kMRMediaRemoteNowPlayingApplicationClientStateDidChange;
extern NSString *kMRNowPlayingPlaybackQueueChangedNotification;
extern NSString *kMRPlaybackQueueContentItemsChangedNotification;
extern NSString *kMRMediaRemoteNowPlayingApplicationDidChangeNotification;
extern NSString *kMRMediaRemoteNowPlayingInfoAlbum;
extern NSString *kMRMediaRemoteNowPlayingInfoArtist;
extern NSString *kMRMediaRemoteNowPlayingInfoTitle;
extern NSString *kMRMediaRemoteNowPlayingInfoArtworkData;
typedef enum {
kMRPlay = 0,
kMRPause = 1,
kMRTogglePlayPause = 2,
kMRNextTrack = 4,
kMRPreviousTrack = 5,
} MRCommand;
extern Boolean MRMediaRemoteSendCommand(MRCommand command, id userInfo);

View File

@ -6,6 +6,8 @@
// Copyright © 2019 Shadowfacts. All rights reserved. // Copyright © 2019 Shadowfacts. All rights reserved.
// //
// Copied from https://github.com/pigigaldi/Pock/blob/852679a4882d0e9c5b3d8473eb9b9fbf7bef837f/Pock/Private/NSTouchBar.h
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
extern void DFRElementSetControlStripPresenceForIdentifier(_Nonnull NSTouchBarItemIdentifier, BOOL); extern void DFRElementSetControlStripPresenceForIdentifier(_Nonnull NSTouchBarItemIdentifier, BOOL);

View File

@ -7,3 +7,4 @@
// //
#import "NSTouchBar.h" #import "NSTouchBar.h"
#import "MRMediaRemote.h"

View File

@ -1,18 +0,0 @@
//
// NowPlayingWidget.swift
// Underbar
//
// Created by Shadowfacts on 7/13/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import Cocoa
class NowPlayingWidget: TouchBarWidget {
override init() {
super.init()
item = NSButtonTouchBarItem(identifier: .nowPlaying, title: "Test", target: nil, action: nil)
}
}

View File

@ -1,24 +0,0 @@
//
// TouchBarWidget.swift
// Underbar
//
// Created by Shadowfacts on 7/13/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import Cocoa
class TouchBarWidget: NSObject {
var item: NSTouchBarItem!
override init() {
super.init()
}
convenience init(item: NSTouchBarItem) {
self.init()
self.item = item
}
}