From 039c5714c64dbdaa6f3045d64ec519fef4813309 Mon Sep 17 00:00:00 2001 From: Vinoth Ramiah Date: Fri, 26 Aug 2022 12:16:06 +0530 Subject: [PATCH 1/3] Placeholder menu option and code to configure View --- Timer/MVMainView.swift | 20 ++++++++++++++++++++ Timer/MVTimerController.swift | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/Timer/MVMainView.swift b/Timer/MVMainView.swift index 1f59288..291a805 100644 --- a/Timer/MVMainView.swift +++ b/Timer/MVMainView.swift @@ -52,9 +52,20 @@ class MVMainView: NSView { submenu.addItem(soundItem) } self.soundMenuItems.first?.state = .on + + let menuItemViewConfig = NSMenuItem( + title: "View", + action: nil, + keyEquivalent: "" + ) + let submenuViewConfig = NSMenu() + submenuViewConfig.autoenablesItems = false + self.contextMenu?.addItem(menuItem!) self.contextMenu?.addItem(menuItemSoundChoice) self.contextMenu?.setSubmenu(submenu, for: menuItemSoundChoice) + self.contextMenu?.addItem(menuItemViewConfig) + self.contextMenu?.setSubmenu(submenuViewConfig, for: menuItemViewConfig) let notificationCenter = NotificationCenter.default @@ -102,6 +113,15 @@ class MVMainView: NSView { } } + @objc func toggleViewItemState(_ sender: NSMenuItem) { + var value = sender.state == .on ? true : false + value.toggle() + switch sender { + default: + break + } + } + deinit { NotificationCenter.default.removeObserver(self) } diff --git a/Timer/MVTimerController.swift b/Timer/MVTimerController.swift index ecebb3a..d9f1c3e 100644 --- a/Timer/MVTimerController.swift +++ b/Timer/MVTimerController.swift @@ -105,4 +105,12 @@ class MVTimerController: NSWindowController { self.soundURL = nil } } + + func setViewState(_ value: Bool, forKey viewConfigKey: String) { + let state: NSControl.StateValue = value ? .on : .off + switch viewConfigKey { + default: + break + } + } } From 03ae203177f362b64568bc2ef4071826165f62bd Mon Sep 17 00:00:00 2001 From: Vinoth Ramiah Date: Fri, 26 Aug 2022 12:20:22 +0530 Subject: [PATCH 2/3] Load and save View config from UserDefaults --- Timer/AppDelegate.swift | 6 +++++- Timer/MVTimerController.swift | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Timer/AppDelegate.swift b/Timer/AppDelegate.swift index 9cb5a4d..8fab7c0 100644 --- a/Timer/AppDelegate.swift +++ b/Timer/AppDelegate.swift @@ -20,6 +20,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele func applicationDidFinishLaunching(_ aNotification: Notification) { let controller = MVTimerController() + controller.isMainController = true controllers.append(controller) self.addBadgeToDock(controller: controller) @@ -81,6 +82,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele @objc func newDocument(_ sender: AnyObject?) { let controller = MVTimerController(closeToWindow: NSApplication.shared.keyWindow) controller.window?.level = self.windowLevel() + controller.isMainController = controllers.isEmpty controllers.append(controller) } @@ -109,6 +111,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele } private func registerDefaults() { - UserDefaults.standard.register(defaults: [MVUserDefaultsKeys.staysOnTop: false]) + UserDefaults.standard.register(defaults: [ + MVUserDefaultsKeys.staysOnTop: false, + ]) } } diff --git a/Timer/MVTimerController.swift b/Timer/MVTimerController.swift index d9f1c3e..6d97bd9 100644 --- a/Timer/MVTimerController.swift +++ b/Timer/MVTimerController.swift @@ -8,6 +8,8 @@ class MVTimerController: NSWindowController { private var audioPlayer: AVAudioPlayer? // player must be kept in memory private var soundURL = Bundle.main.url(forResource: "alert-sound", withExtension: "caf") + var isMainController: Bool = false + convenience init() { let mainView = MVMainView(frame: NSRect.zero) @@ -25,6 +27,8 @@ class MVTimerController: NSWindowController { self.windowFrameAutosaveName = "TimerWindowAutosaveFrame" window.makeKeyAndOrderFront(self) + + loadViewStateFromUserDefaults() } convenience init(closeToWindow: NSWindow?) { @@ -107,10 +111,26 @@ class MVTimerController: NSWindowController { } func setViewState(_ value: Bool, forKey viewConfigKey: String) { + setViewState(value, forKey: viewConfigKey, save: isMainController) + } + + private func setViewState(_ value: Bool, forKey viewConfigKey: String, save: Bool) { let state: NSControl.StateValue = value ? .on : .off switch viewConfigKey { default: break } + if save { + UserDefaults.standard.set(value, forKey: viewConfigKey) + } + } + + private func loadViewStateFromUserDefaults() { + let keys: [String] = [ + ] + for key in keys { + let value = UserDefaults.standard.bool(forKey: key) + setViewState(value, forKey: key, save: false) + } } } From 4e4ce5173daecb2da792343287d579e4195254c8 Mon Sep 17 00:00:00 2001 From: Vinoth Ramiah Date: Wed, 24 Aug 2022 18:28:36 +0530 Subject: [PATCH 3/3] Option to disable visual change on focus change --- Timer/AppDelegate.swift | 1 + Timer/MVClockView.swift | 16 ++++++++++++++-- Timer/MVMainView.swift | 10 ++++++++++ Timer/MVTimerController.swift | 4 ++++ Timer/MVUserDefaultsKeys.swift | 1 + 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Timer/AppDelegate.swift b/Timer/AppDelegate.swift index 8fab7c0..eb1e5db 100644 --- a/Timer/AppDelegate.swift +++ b/Timer/AppDelegate.swift @@ -113,6 +113,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele private func registerDefaults() { UserDefaults.standard.register(defaults: [ MVUserDefaultsKeys.staysOnTop: false, + MVUserDefaultsKeys.appearanceChangeOnFocusChange: true ]) } } diff --git a/Timer/MVClockView.swift b/Timer/MVClockView.swift index 1f27d8e..0515d85 100644 --- a/Timer/MVClockView.swift +++ b/Timer/MVClockView.swift @@ -160,6 +160,13 @@ class MVClockView: NSControl { self.updateClockFaceView() } + func appearanceChangeOnFocusChange(_ change: Bool) { + clockFaceView.appearanceChangeOnFocus = change + arrowView.appearanceChangeOnFocus = change + progressView.appearanceChangeOnFocus = change + self.needsDisplay = true + } + private func updateClockFaceView(highlighted: Bool = false) { clockFaceView.update(highlighted: highlighted) } @@ -526,6 +533,7 @@ class MVClockProgressView: NSView { self.needsDisplay = true } } + var appearanceChangeOnFocus: Bool = true convenience init() { self.init(frame: NSRect(x: 0, y: 0, width: 116, height: 116)) @@ -583,7 +591,7 @@ class MVClockProgressView: NSView { transform.translate(x: -center.x, y: -center.y) (transform as NSAffineTransform).concat() - let image = NSImage(named: windowHasFocus ? "progress" : "progress-unfocus") + let image = NSImage(named: windowHasFocus || !appearanceChangeOnFocus ? "progress" : "progress-unfocus") image?.draw(in: self.bounds) ctx?.restoreGraphicsState() @@ -601,6 +609,7 @@ class MVClockArrowView: NSControl { } } var actionMouseUp: Selector? + var appearanceChangeOnFocus: Bool = true private var center = CGPoint.zero convenience init(center: CGPoint) { @@ -647,7 +656,7 @@ class MVClockArrowView: NSControl { path.transform(using: transform) let windowHasFocus = self.window?.isKeyWindow ?? false - if windowHasFocus { + if windowHasFocus || !appearanceChangeOnFocus { let ratio: CGFloat = 0.5 NSColor( srgbRed: 0.1734 + ratio * (0.2235 - 0.1734), @@ -737,6 +746,7 @@ class MVClockArrowView: NSControl { class MVClockFaceView: NSView { private var _image: NSImage? + var appearanceChangeOnFocus: Bool = true func update(highlighted: Bool = false) { // Load the appropriate image for the clock face @@ -744,6 +754,8 @@ class MVClockFaceView: NSView { if highlighted { imageName = "clock-highlighted" + } else if !appearanceChangeOnFocus { + imageName = "clock" } else { let windowHasFocus = self.window?.isKeyWindow ?? false imageName = windowHasFocus ? "clock" : "clock-unfocus" diff --git a/Timer/MVMainView.swift b/Timer/MVMainView.swift index 291a805..7ed29b4 100644 --- a/Timer/MVMainView.swift +++ b/Timer/MVMainView.swift @@ -16,6 +16,7 @@ class MVMainView: NSView { private var contextMenu: NSMenu? public var menuItem: NSMenuItem? private var soundMenuItems: [NSMenuItem] = [] + var appearanceChangeOnFocusMenuItem: NSMenuItem? // swiftlint:disable unused_setter_value override var menu: NSMenu? { @@ -61,6 +62,13 @@ class MVMainView: NSView { let submenuViewConfig = NSMenu() submenuViewConfig.autoenablesItems = false + appearanceChangeOnFocusMenuItem = NSMenuItem( + title: "Change appearance when not in focus", + action: #selector(self.toggleViewItemState), + keyEquivalent: "" + ) + submenuViewConfig.addItem(appearanceChangeOnFocusMenuItem!) + self.contextMenu?.addItem(menuItem!) self.contextMenu?.addItem(menuItemSoundChoice) self.contextMenu?.setSubmenu(submenu, for: menuItemSoundChoice) @@ -117,6 +125,8 @@ class MVMainView: NSView { var value = sender.state == .on ? true : false value.toggle() switch sender { + case appearanceChangeOnFocusMenuItem: + self.controller?.setViewState(value, forKey: MVUserDefaultsKeys.appearanceChangeOnFocusChange) default: break } diff --git a/Timer/MVTimerController.swift b/Timer/MVTimerController.swift index 6d97bd9..5cd349b 100644 --- a/Timer/MVTimerController.swift +++ b/Timer/MVTimerController.swift @@ -117,6 +117,9 @@ class MVTimerController: NSWindowController { private func setViewState(_ value: Bool, forKey viewConfigKey: String, save: Bool) { let state: NSControl.StateValue = value ? .on : .off switch viewConfigKey { + case MVUserDefaultsKeys.appearanceChangeOnFocusChange: + mainView.appearanceChangeOnFocusMenuItem?.state = state + clockView.appearanceChangeOnFocusChange(value) default: break } @@ -127,6 +130,7 @@ class MVTimerController: NSWindowController { private func loadViewStateFromUserDefaults() { let keys: [String] = [ + MVUserDefaultsKeys.appearanceChangeOnFocusChange ] for key in keys { let value = UserDefaults.standard.bool(forKey: key) diff --git a/Timer/MVUserDefaultsKeys.swift b/Timer/MVUserDefaultsKeys.swift index d400c83..1078f93 100644 --- a/Timer/MVUserDefaultsKeys.swift +++ b/Timer/MVUserDefaultsKeys.swift @@ -1,3 +1,4 @@ struct MVUserDefaultsKeys { static let staysOnTop = "staysOnTop" + static let appearanceChangeOnFocusChange = "appearanceChangeOnFocusChange" }