From ffc79f00e5e93965a833aa26cd45e93cc2584985 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 23 Oct 2019 00:34:04 +0800 Subject: [PATCH 1/6] fix: player always switch to control state when track changed issue --- Song Rating/Controllers/PlayerPanelViewController.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Song Rating/Controllers/PlayerPanelViewController.swift b/Song Rating/Controllers/PlayerPanelViewController.swift index 8466506..c489add 100644 --- a/Song Rating/Controllers/PlayerPanelViewController.swift +++ b/Song Rating/Controllers/PlayerPanelViewController.swift @@ -7,6 +7,7 @@ // import Cocoa +import os protocol PlayerPanelViewControllerDelegate: class { func playerPanelViewController(_ playerPanelViewController: PlayerPanelViewController, menuButtonPressed button: NSButton) @@ -25,7 +26,7 @@ final class PlayerPanelViewController: NSViewController { var isStop = false { didSet { - stateDidUpdate(.control) + stateDidUpdate(isStop ? .control : .info) } } var state: State = .info { @@ -49,7 +50,7 @@ extension PlayerPanelViewController { override func viewDidLoad() { super.viewDidLoad() - + playerInfoView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(playerInfoView) NSLayoutConstraint.activate([ @@ -120,6 +121,7 @@ extension PlayerPanelViewController { } func stateDidUpdate(_ state: State) { + os_log("%{public}s[%{public}ld], %{public}s: %{public}s", ((#file as NSString).lastPathComponent), #line, #function, String(describing: state)) playerControlView.backwardButton.isEnabled = !isStop playerControlView.forwardButton.isEnabled = !isStop From 6b3f2989c402c0eaa8b3f876702820039932fb8e Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 23 Oct 2019 01:58:33 +0800 Subject: [PATCH 2/6] feat: add DispatchQueue.once for once task --- Song Rating/Helper/DispatchQueue.swift | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Song Rating/Helper/DispatchQueue.swift diff --git a/Song Rating/Helper/DispatchQueue.swift b/Song Rating/Helper/DispatchQueue.swift new file mode 100644 index 0000000..d73c3d1 --- /dev/null +++ b/Song Rating/Helper/DispatchQueue.swift @@ -0,0 +1,33 @@ +// +// DispatchQueue.swift +// Song Rating +// +// Created by Cirno MainasuK on 2019-10-23. +// Copyright © 2019 Cirno MainasuK. All rights reserved. +// + +import Cocoa + +public extension DispatchQueue { + + private static var _onceTracker = [String]() + + /** + Executes a block of code, associated with a unique token, only once. The code is thread safe and will + only execute the code once even in the presence of multithreaded calls. + + - parameter token: A unique reverse DNS style name such as com.vectorform. or a GUID + - parameter block: Block to execute once + */ + class func once(token: String, block: () -> Void) { + objc_sync_enter(self); defer { objc_sync_exit(self) } + + if _onceTracker.contains(token) { + return + } + + _onceTracker.append(token) + block() + } + +} From 2a07d29a8eafd2c7486360474a78fd6f765c4f38 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 23 Oct 2019 02:00:44 +0800 Subject: [PATCH 3/6] fix: popover follow menu bar focus point cause jump between screens issue. Also set popover window level make it always on top --- .../Controls/MenuBarRatingControl.swift | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Song Rating/Controls/MenuBarRatingControl.swift b/Song Rating/Controls/MenuBarRatingControl.swift index 7edb558..12ab2be 100644 --- a/Song Rating/Controls/MenuBarRatingControl.swift +++ b/Song Rating/Controls/MenuBarRatingControl.swift @@ -268,9 +268,32 @@ extension MenuBarRatingControl { popover.delegate = popoverProxy // FIXME: should relative to windows - popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY) + // popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY) popover.contentViewController?.view.window?.makeKey() + + // Ref: https://stackoverflow.com/questions/48594212/how-to-open-a-nspopover-at-a-distance-from-the-system-bar/48604455#48604455 + // TODO: fix windows leaking issue + let invisibleWindow = NSWindow(contentRect: NSMakeRect(0, 0, 20, 5), styleMask: .borderless, backing: .buffered, defer: false) + invisibleWindow.backgroundColor = .red + invisibleWindow.alphaValue = 0 + + // find the coordinates of the statusBarItem in screen space + let buttonRect:NSRect = button.convert(button.bounds, to: nil) + let screenRect:NSRect = button.window!.convertToScreen(buttonRect) + + // calculate the bottom center position (10 is the half of the window width) + let posX = screenRect.origin.x + (screenRect.width / 2) - 10 + let posY = screenRect.origin.y + // position and show the window + invisibleWindow.setFrameOrigin(NSPoint(x: posX, y: posY)) + invisibleWindow.makeKeyAndOrderFront(self) + invisibleWindow.level = .floating // make popover always on top + + // position and show the NSPopover + popover.show(relativeTo: invisibleWindow.contentView!.frame, of: invisibleWindow.contentView!, preferredEdge: NSRectEdge.minY) + popover.contentViewController?.view.window?.makeKey() // fix popover not get focus issue + undetachedPopover = popover } From 12ced4da5ffec9aaa422d5ad74c72e3b6a9c03be Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 23 Oct 2019 02:01:57 +0800 Subject: [PATCH 4/6] fix: send message on SBApplication cause app wake up when not running issue. resolve: #7 --- Song Rating.xcodeproj/project.pbxproj | 4 ++++ Song Rating/Controls/MenuBarRatingControl.swift | 10 +++++++--- Song Rating/iTunes/iTunesRadioStation.swift | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Song Rating.xcodeproj/project.pbxproj b/Song Rating.xcodeproj/project.pbxproj index aaba3c0..b4bab5d 100644 --- a/Song Rating.xcodeproj/project.pbxproj +++ b/Song Rating.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ DB95216A22CB186F007FCF40 /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB95216922CB186F007FCF40 /* WindowManager.swift */; }; DB95216E22CB1CB8007FCF40 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB95216D22CB1CB8007FCF40 /* AboutViewController.swift */; }; DB95217222CB3E68007FCF40 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB95217122CB3E68007FCF40 /* PreferencesViewController.swift */; }; + DB9D9AF0235F7974008C53C3 /* DispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D9AEF235F7974008C53C3 /* DispatchQueue.swift */; }; FE421476F34E641428B030E9 /* Pods_Song_Rating.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DFF0EB36C01E667D4778CCC /* Pods_Song_Rating.framework */; }; /* End PBXBuildFile section */ @@ -105,6 +106,7 @@ DB95216922CB186F007FCF40 /* WindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManager.swift; sourceTree = ""; }; DB95216D22CB1CB8007FCF40 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; DB95217122CB3E68007FCF40 /* PreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = ""; }; + DB9D9AEF235F7974008C53C3 /* DispatchQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchQueue.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -246,6 +248,7 @@ DB89C9FF22E37826003981F5 /* OSVersionHelper.swift */, DB05F0852354CA5800CE6DF9 /* NSViewPreview.swift */, DB05F0872354CA6B00CE6DF9 /* NSViewControllerPreview.swift */, + DB9D9AEF235F7974008C53C3 /* DispatchQueue.swift */, DB33438A235E103200B45ED0 /* ExceptionCatcher.h */, DB334388235E102600B45ED0 /* ExceptionCatcher.m */, DB334387235E102500B45ED0 /* Song Rating-Bridging-Header.h */, @@ -485,6 +488,7 @@ DB89C9F322E2D766003981F5 /* MenuBarIcon.swift in Sources */, DB106CA422CA3C7300502D7C /* Star.swift in Sources */, DB95216E22CB1CB8007FCF40 /* AboutViewController.swift in Sources */, + DB9D9AF0235F7974008C53C3 /* DispatchQueue.swift in Sources */, DB424A352307259800230C7E /* iTunesTrack.swift in Sources */, DB106C4622C53D4B00502D7C /* AppDelegate.swift in Sources */, DB424A3E2308936F00230C7E /* AutoScrollTextField.swift in Sources */, diff --git a/Song Rating/Controls/MenuBarRatingControl.swift b/Song Rating/Controls/MenuBarRatingControl.swift index 12ab2be..42df256 100644 --- a/Song Rating/Controls/MenuBarRatingControl.swift +++ b/Song Rating/Controls/MenuBarRatingControl.swift @@ -93,7 +93,7 @@ final class MenuBarRatingControl { updateMenuBar() } } - private(set) var playState: PlayInfo.PlayerState? { + private(set) var playState: PlayInfo.PlayerState = .unknown { didSet { if playState == .unknown { undetachedPopover?.close() @@ -152,10 +152,11 @@ extension MenuBarRatingControl { let playingWidth = margin + ratingControl.starsImage.size.width let pauseWidth = margin + CGFloat(2) * ratingControl.spacing + ratingControl.starSize.width - statusItem.length = !isStop ? playingWidth : pauseWidth + statusItem.length = !isStop ? playingWidth : pauseWidth statusItem.button?.image = !isStop ? ratingControl.starsImage : menuBarIcon.image statusItem.button?.setButtonType(!isStop ? .momentaryChange : .onOff) } + } extension MenuBarRatingControl { @@ -238,8 +239,11 @@ extension MenuBarRatingControl { return } + DispatchQueue.once(token: "firstDisplay") { + updateMenuBar() + } + os_log("%{public}s[%{public}ld], %{public}s: window size change to %{public}s", ((#file as NSString).lastPathComponent), #line, #function, window.frame.debugDescription) - } } diff --git a/Song Rating/iTunes/iTunesRadioStation.swift b/Song Rating/iTunes/iTunesRadioStation.swift index 6736dbd..c2d1c10 100644 --- a/Song Rating/iTunes/iTunesRadioStation.swift +++ b/Song Rating/iTunes/iTunesRadioStation.swift @@ -25,6 +25,9 @@ final class iTunesRadioStation { var iTunes: iTunesApplication? { let application = SBApplication(bundleIdentifier: OSVersionHelper.bundleIdentifier) + guard application?.isRunning == true else { + return nil + } application?.delegate = self return application } From 6ad435ad80b10836da43fee4ccb3bd803c36ce20 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 23 Oct 2019 02:10:40 +0800 Subject: [PATCH 5/6] chore: add padding between song title and artist label in PlayerInfoView --- Song Rating/Views/PlayerInfoView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Song Rating/Views/PlayerInfoView.swift b/Song Rating/Views/PlayerInfoView.swift index e5a2ed3..5516bb1 100644 --- a/Song Rating/Views/PlayerInfoView.swift +++ b/Song Rating/Views/PlayerInfoView.swift @@ -55,7 +55,7 @@ final class PlayerInfoView: NSView { captionTextField.translatesAutoresizingMaskIntoConstraints = false groupView.addSubview(captionTextField) NSLayoutConstraint.activate([ - captionTextField.topAnchor.constraint(equalTo: titleTextField.bottomAnchor), + captionTextField.topAnchor.constraint(equalTo: titleTextField.bottomAnchor, constant: 4), // padding captionTextField.leadingAnchor.constraint(equalTo: groupView.leadingAnchor), captionTextField.trailingAnchor.constraint(equalTo: groupView.trailingAnchor), captionTextField.bottomAnchor.constraint(equalTo: groupView.bottomAnchor) From 6cf662410169e1b7350bb0851a7e8a4ca0ec9037 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 23 Oct 2019 02:11:22 +0800 Subject: [PATCH 6/6] chore: update version to 1.2.1 (6) --- Song Rating.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Song Rating.xcodeproj/project.pbxproj b/Song Rating.xcodeproj/project.pbxproj index b4bab5d..3ddf9bf 100644 --- a/Song Rating.xcodeproj/project.pbxproj +++ b/Song Rating.xcodeproj/project.pbxproj @@ -657,7 +657,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = A8K92XFF77; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = "Song Rating/Info.plist"; @@ -665,7 +665,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.2.0; + MARKETING_VERSION = 1.2.1; PRODUCT_BUNDLE_IDENTIFIER = "com.mainasuk.Song-Rating"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -685,7 +685,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = A8K92XFF77; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = "Song Rating/Info.plist"; @@ -693,7 +693,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.2.0; + MARKETING_VERSION = 1.2.1; PRODUCT_BUNDLE_IDENTIFIER = "com.mainasuk.Song-Rating"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "";