Skip to content
This repository has been archived by the owner on Jun 26, 2023. It is now read-only.

Commit

Permalink
-1751, you still there?
Browse files Browse the repository at this point in the history
  • Loading branch information
ApolloZhu committed Sep 30, 2018
1 parent de1db50 commit 2b5363c
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 54 deletions.
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [1.0.5] - 2018-09-30
### Fixed
- False alarm about `-1751` apple script error
- Wrongly turning on dark mode when custom schedule spans within a single day

## [1.0.4] - 2018-09-29
### Added
- Simplfied Chinese Translation

### Fixed
- False alarm about `-1751` apple script error

## [1.0.3] - 2018-09-29
### Added
- installer pkg for download
Expand Down
2 changes: 1 addition & 1 deletion Dynamic/Supporting Files/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>4</string>
<string>5</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
Expand Down
5 changes: 4 additions & 1 deletion Dynamic/Supporting Files/zh-Hans.lproj/InfoPlist.strings
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
/* Copyright (human-readable) */
"NSHumanReadableCopyright" = "版权所有 © 2018 自动深色模式。保留所有权利。";

/* Privacy - AppleEvents Sending Usage Description */
"NSAppleEventsUsageDescription" = "“自动深色模式”必须要您的允许才能管理深色模式。";

/* Privacy - Location Usage Description */
"NSLocationUsageDescription" = "自动深色模式以此计算日出日落时间。";
"NSLocationUsageDescription" = "“自动深色模式”需要您允许读取当前位置才能计算日出日落时间。";

7 changes: 5 additions & 2 deletions Dynamic/Supporting Files/zh-Hans.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/* No comment provided by engineer. */
"AppleScript.authorization.error" = "你并未允许“自动深色模式”管理深色模式。";

/* Generic error happened */
"AppleScript.authorization.failed" = "出错了 QAQ";

/* No comment provided by engineer. */
"AppleScript.authorization.instruction" = "我们将带您到“系统偏好设置”。该设置需要您重新打开“自动深色模式”才会生效。";

/* Please try again */
"AppleScript.errorOSInvalidID" = "出错了 QAQ";
/* something went wrong. But it's okay */
"AppleScript.execute.error" = "未能切换暗色模式";

/* Scare the user so they report bugs. */
"appleScriptExecution.error.title" = "告诉开发者 TA 们又写严重的 Bug 了";
Expand Down
2 changes: 1 addition & 1 deletion Dynamic/Utilities/Appearance/AppearanceSwitcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import AppKit

let darkModeUserDefaultsKey = "AppleInterfaceStyle"

enum AppleInterfaceStyle: String {
public enum AppleInterfaceStyle: String {
case aqua
case darkAqua
}
Expand Down
19 changes: 12 additions & 7 deletions Dynamic/Utilities/Appearance/AppleScriptHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,18 @@ extension AppleScript {
var errorInfo: NSDictionary? = nil
let script = NSAppleScript(contentsOf: self.url, error: &errorInfo)
script?.executeAndReturnError(&errorInfo)
showError(errorInfo)
showError(errorInfo, title: NSLocalizedString(
"AppleScript.execute.error",
value: "Failed to Toggle Dark Mode",
comment: "something went wrong. But it's okay"
))
}
}
}

extension AppleScript {
public static func checkPermission(
executeWhenAuthorized onSuccess: @escaping () -> Void = { }
onSuccess: @escaping () -> Void = { }
) {
requestPermission { authorized in
if authorized { return onSuccess() }
Expand Down Expand Up @@ -99,25 +103,26 @@ extension AppleScript {
return process(true)
case errAEEventNotPermitted:
break
case errOSAInvalidID, -1751: // These two are supposed to be the same
case errOSAInvalidID, -1751,
errAEEventWouldRequireUserConsent,
procNotFound:
#warning("Figure out what causes this")
if retryOnInternalError {
log(.error, "Dynamic - OSStatus %{public}d", status)
requestPermission(retryOnInternalError: false, then: process)
} else {
runModal(ofNSAlert: { alert in
alert.messageText = NSLocalizedString(
"AppleScript.errorOSInvalidID",
"AppleScript.authorization.failed",
value: "Something Went Wrong",
comment: "Please try again"
comment: "Generic error happened"
)
alert.informativeText = "\(status)"
})
}
case errAEEventWouldRequireUserConsent, procNotFound:
showCriticalErrorMessage("\(status)")
default:
log(.fault, "Dynamic - Unhandled OSStatus %{public}d", status)
showCriticalErrorMessage("\(status)")
}
process(false)
}
Expand Down
16 changes: 11 additions & 5 deletions Dynamic/Utilities/Brightness/ScreenBrightnessObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,31 @@ final class ScreenBrightnessObserver: NSObject {
)
updateForBrightnessChange()
}
@objc private func updateForBrightnessChange() {

public var mode: AppleInterfaceStyle? {
let brightness = NSScreen.brightness
let threshold = preferences.brightnessThreshold
switch brightness {
case 0..<threshold:
AppleInterfaceStyle.darkAqua.enable()
return .darkAqua
case threshold...1:
AppleInterfaceStyle.aqua.enable()
return .aqua
default:
// The NoSense here is from the "AppleNoSenseDisplay" in IOKit
log(.fault, "Dynamic - No Sense Brightness Fetched")
return nil
}
}

@objc private func updateForBrightnessChange() {
guard let mode = self.mode else { return }
AppleScript.checkPermission(onSuccess: mode.enable)
}

public func stop() {
DistributedNotificationCenter.default().removeObserver(self)
}

deinit {
stop()
// MARK: - Update Anyways
Expand All @@ -53,7 +60,6 @@ final class ScreenBrightnessObserver: NSObject {
)
}


private override init() {
super.init()
// Listen to Appearance Changes
Expand Down
4 changes: 2 additions & 2 deletions Dynamic/Utilities/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ extension Preferences {
{ _, change in changeHandler(change) }
}
handles = [
observe(\.adjustForBrightness, observeInitial: true) { change in
observe(\.adjustForBrightness) { change in
ScreenBrightnessObserver.shared.stop()
if change.newValue == true {
ScreenBrightnessObserver.shared.start()
}
},
observe(\.scheduled, observeInitial: true) { change in
observe(\.scheduled) { change in
if change.newValue == true {
Scheduler.shared.schedule()
} else {
Expand Down
86 changes: 59 additions & 27 deletions Dynamic/Utilities/Scheduler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ public final class Scheduler: NSObject, CLLocationManagerDelegate {
public static let shared = Scheduler()
private override init() { super.init() }

private var isScheduling = false
public func schedule() {
if isScheduling { return }
isScheduling = true
private func requestLocationUpdate() -> Bool {
switch CLLocationManager.authorizationStatus() {
case .authorizedAlways, .notDetermined:
manager.stopUpdatingLocation()
Expand All @@ -28,79 +25,109 @@ public final class Scheduler: NSObject, CLLocationManagerDelegate {
} else {
manager.startUpdatingLocation()
}
return true
default:
return false
}
}

private var isScheduling = false
public func schedule() {
if isScheduling { return }
isScheduling = true
if !requestLocationUpdate() {
scheduleAtCachedLocation()
}
}

public typealias StyleProcessor = (AppleInterfaceStyle?) -> Void
private var _callback: StyleProcessor?
private var callback: StyleProcessor? {
get {
defer { _callback = nil }
return _callback
}
set {
_callback = newValue
}
}
public func getCurrentMode(then process: @escaping StyleProcessor) {
callback = process
if requestLocationUpdate() { return }
callback?(nil)
}

private var task: Task?

private func schedule(atLocation coordinate: CLLocationCoordinate2D?) {
defer { isScheduling = false }
guard preferences.scheduled else { return cancel() }
public func mode(atLocation coordinate: CLLocationCoordinate2D?) -> (style: AppleInterfaceStyle, date: Date?) {
let now = Date()
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: now)!
if let coordinate = coordinate
, CLLocationCoordinate2DIsValid(coordinate)
, preferences.scheduleZenithType != .custom {
defer { removeAllNotifications() }
let scheduledDate: Date
let solar = Solar(for: now, coordinate: coordinate)!
let dates = solar.sunriseSunsetTime
#warning("FIXME: Having trouble figuring out time zone")
if now < dates.sunrise {
AppleInterfaceStyle.darkAqua.enable()
scheduledDate = dates.sunrise
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: now)!
let pastSolar = Solar(for: yesterday, coordinate: coordinate)!
preferences.scheduleStart = pastSolar.sunriseSunsetTime.sunset
preferences.scheduleEnd = scheduledDate
return (.darkAqua, scheduledDate)
} else {
let futureSolar = Solar(for: tomorrow, coordinate: coordinate)!
let futureDates = futureSolar.sunriseSunsetTime
if now < dates.sunset {
AppleInterfaceStyle.aqua.enable()
scheduledDate = dates.sunset
preferences.scheduleStart = scheduledDate
preferences.scheduleEnd = futureDates.sunrise
return (.aqua, scheduledDate)
} else { // after sunset
AppleInterfaceStyle.darkAqua.enable()
preferences.scheduleStart = dates.sunset
scheduledDate = futureDates.sunrise
preferences.scheduleEnd = scheduledDate
return (.darkAqua, scheduledDate)
}
}
return task = Plan.at(scheduledDate).do(onElapse: schedule)
}
if preferences.scheduleZenithType != .custom {
preferences.scheduleZenithType = .custom
}
#warning("FIXME: This is gonna be a catastrophe when a user moves across timezone")
let current = Calendar.current.dateComponents([.hour, .minute], from: now)
let start = Calendar.current.dateComponents(
[.hour, .minute], from: preferences.scheduleStart
)
let end = Calendar.current.dateComponents(
[.hour, .minute], from: preferences.scheduleEnd
)
let scheduledDate: Date!
if start == end { return (.current, nil) }
if current < end {
AppleInterfaceStyle.darkAqua.enable()
scheduledDate = Calendar.current.date(
return (.darkAqua, Calendar.current.date(
bySettingHour: end.hour!, minute: end.minute!, second: 0, of: now
)
))
} else if current < start {
AppleInterfaceStyle.aqua.enable()
scheduledDate = Calendar.current.date(
return (.aqua, Calendar.current.date(
bySettingHour: start.hour!, minute: start.minute!, second: 0, of: now
)
} else {
AppleInterfaceStyle.darkAqua.enable()
scheduledDate = Calendar.current.date(
))
} else if start > end {
return (.darkAqua, Calendar.current.date(
bySettingHour: end.hour!, minute: end.minute!, second: 0, of: tomorrow
)
))
} else {
return (.aqua, Calendar.current.date(
bySettingHour: start.hour!, minute: start.minute!, second: 0, of: tomorrow
))
}
task = Plan.at(scheduledDate).do(onElapse: schedule)
}

private func schedule(atLocation coordinate: CLLocationCoordinate2D?) {
defer { isScheduling = false }
removeAllNotifications()
let decision = mode(atLocation: coordinate)
AppleScript.checkPermission(onSuccess: decision.style.enable)
guard let date = decision.date else { return }
task = Plan.at(date).do(onElapse: schedule)
}

public func cancel() {
Expand Down Expand Up @@ -128,7 +155,12 @@ public final class Scheduler: NSObject, CLLocationManagerDelegate {
guard let location = locations.last else { return }
manager.stopUpdatingLocation()
preferences.location = location
schedule(atLocation: location.coordinate)
let coordinate = location.coordinate
if isScheduling {
schedule(atLocation: coordinate)
} else {
callback?(mode(atLocation: coordinate).style)
}
}

public func locationManager(_ manager: CLLocationManager,
Expand Down
11 changes: 10 additions & 1 deletion Dynamic/View Controller/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,17 @@ func start() {
started = true
DispatchQueue.main.async {
Preferences.setupObservers()
AppleScript.checkPermission()
_ = ScreenBrightnessObserver.shared
AppleScript.checkPermission {
DispatchQueue.main.async {
Scheduler.shared.getCurrentMode {
guard let style = $0
?? ScreenBrightnessObserver.shared.mode
else { return }
style.enable()
}
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Dynamic/View Controller/zh-Hans.lproj/Main.strings
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
"LE2-aR-0XJ.title" = "前置所有窗口";

/* Class = "NSTextFieldCell"; title = "Dynamic Dark Mode needs to send commands to the built-in \"System Events\" in order to toggle dark mode for you."; ObjectID = "mGd-Ks-iSW"; */
"mGd-Ks-iSW.title" = "“自动深色模式”需要能够向系统自带的“System Events”发送请求才能为您切换深色模式。";
"mGd-Ks-iSW.title" = "“自动深色模式”需要能够向系统自带的“System Events”(系统事件)发送请求才能为您切换深色模式。";

/* Class = "NSTextFieldCell"; title = "Shortcut"; ObjectID = "MI9-bf-6dt"; */
"MI9-bf-6dt.title" = "切换快捷键";
Expand Down
2 changes: 1 addition & 1 deletion DynamicLauncher/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>4</string>
<string>5</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Instead of looking for the switch for dark mode in System Preferences, just clic

### Latest Release

[Dynamic Dark Mode v1.0 (4) Release Page](https://github.com/ApolloZhu/Dynamic-Dark-Mode/releases/tag/1.0.4)
[Dynamic Dark Mode v1.0 (5) Release Page](https://github.com/ApolloZhu/Dynamic-Dark-Mode/releases/tag/1.0.5)

### Not Yet, But I'm Trying:

Expand Down

0 comments on commit 2b5363c

Please sign in to comment.