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

Commit 2b5363c

Browse files
committed
-1751, you still there?
1 parent de1db50 commit 2b5363c

File tree

13 files changed

+112
-54
lines changed

13 files changed

+112
-54
lines changed

CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

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

912
## [1.0.4] - 2018-09-29
1013
### Added
1114
- Simplfied Chinese Translation
1215

13-
### Fixed
14-
- False alarm about `-1751` apple script error
15-
1616
## [1.0.3] - 2018-09-29
1717
### Added
1818
- installer pkg for download

Dynamic/Supporting Files/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<key>CFBundleShortVersionString</key>
2020
<string>1.0</string>
2121
<key>CFBundleVersion</key>
22-
<string>4</string>
22+
<string>5</string>
2323
<key>ITSAppUsesNonExemptEncryption</key>
2424
<false/>
2525
<key>LSApplicationCategoryType</key>

Dynamic/Supporting Files/zh-Hans.lproj/InfoPlist.strings

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
/* Copyright (human-readable) */
55
"NSHumanReadableCopyright" = "版权所有 © 2018 自动深色模式。保留所有权利。";
66

7+
/* Privacy - AppleEvents Sending Usage Description */
8+
"NSAppleEventsUsageDescription" = "“自动深色模式”必须要您的允许才能管理深色模式。";
9+
710
/* Privacy - Location Usage Description */
8-
"NSLocationUsageDescription" = "自动深色模式以此计算日出日落时间。";
11+
"NSLocationUsageDescription" = "“自动深色模式”需要您允许读取当前位置才能计算日出日落时间。";
912

Dynamic/Supporting Files/zh-Hans.lproj/Localizable.strings

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/* No comment provided by engineer. */
22
"AppleScript.authorization.error" = "你并未允许“自动深色模式”管理深色模式。";
33

4+
/* Generic error happened */
5+
"AppleScript.authorization.failed" = "出错了 QAQ";
6+
47
/* No comment provided by engineer. */
58
"AppleScript.authorization.instruction" = "我们将带您到“系统偏好设置”。该设置需要您重新打开“自动深色模式”才会生效。";
69

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

1013
/* Scare the user so they report bugs. */
1114
"appleScriptExecution.error.title" = "告诉开发者 TA 们又写严重的 Bug 了";

Dynamic/Utilities/Appearance/AppearanceSwitcher.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import AppKit
1414

1515
let darkModeUserDefaultsKey = "AppleInterfaceStyle"
1616

17-
enum AppleInterfaceStyle: String {
17+
public enum AppleInterfaceStyle: String {
1818
case aqua
1919
case darkAqua
2020
}

Dynamic/Utilities/Appearance/AppleScriptHelper.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,18 @@ extension AppleScript {
4040
var errorInfo: NSDictionary? = nil
4141
let script = NSAppleScript(contentsOf: self.url, error: &errorInfo)
4242
script?.executeAndReturnError(&errorInfo)
43-
showError(errorInfo)
43+
showError(errorInfo, title: NSLocalizedString(
44+
"AppleScript.execute.error",
45+
value: "Failed to Toggle Dark Mode",
46+
comment: "something went wrong. But it's okay"
47+
))
4448
}
4549
}
4650
}
4751

4852
extension AppleScript {
4953
public static func checkPermission(
50-
executeWhenAuthorized onSuccess: @escaping () -> Void = { }
54+
onSuccess: @escaping () -> Void = { }
5155
) {
5256
requestPermission { authorized in
5357
if authorized { return onSuccess() }
@@ -99,25 +103,26 @@ extension AppleScript {
99103
return process(true)
100104
case errAEEventNotPermitted:
101105
break
102-
case errOSAInvalidID, -1751: // These two are supposed to be the same
106+
case errOSAInvalidID, -1751,
107+
errAEEventWouldRequireUserConsent,
108+
procNotFound:
103109
#warning("Figure out what causes this")
104110
if retryOnInternalError {
105111
log(.error, "Dynamic - OSStatus %{public}d", status)
106112
requestPermission(retryOnInternalError: false, then: process)
107113
} else {
108114
runModal(ofNSAlert: { alert in
109115
alert.messageText = NSLocalizedString(
110-
"AppleScript.errorOSInvalidID",
116+
"AppleScript.authorization.failed",
111117
value: "Something Went Wrong",
112-
comment: "Please try again"
118+
comment: "Generic error happened"
113119
)
114120
alert.informativeText = "\(status)"
115121
})
116122
}
117-
case errAEEventWouldRequireUserConsent, procNotFound:
118-
showCriticalErrorMessage("\(status)")
119123
default:
120124
log(.fault, "Dynamic - Unhandled OSStatus %{public}d", status)
125+
showCriticalErrorMessage("\(status)")
121126
}
122127
process(false)
123128
}

Dynamic/Utilities/Brightness/ScreenBrightnessObserver.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,31 @@ final class ScreenBrightnessObserver: NSObject {
2727
)
2828
updateForBrightnessChange()
2929
}
30-
31-
@objc private func updateForBrightnessChange() {
30+
31+
public var mode: AppleInterfaceStyle? {
3232
let brightness = NSScreen.brightness
3333
let threshold = preferences.brightnessThreshold
3434
switch brightness {
3535
case 0..<threshold:
36-
AppleInterfaceStyle.darkAqua.enable()
36+
return .darkAqua
3737
case threshold...1:
38-
AppleInterfaceStyle.aqua.enable()
38+
return .aqua
3939
default:
4040
// The NoSense here is from the "AppleNoSenseDisplay" in IOKit
4141
log(.fault, "Dynamic - No Sense Brightness Fetched")
42+
return nil
4243
}
4344
}
4445

46+
@objc private func updateForBrightnessChange() {
47+
guard let mode = self.mode else { return }
48+
AppleScript.checkPermission(onSuccess: mode.enable)
49+
}
50+
4551
public func stop() {
4652
DistributedNotificationCenter.default().removeObserver(self)
4753
}
54+
4855
deinit {
4956
stop()
5057
// MARK: - Update Anyways
@@ -53,7 +60,6 @@ final class ScreenBrightnessObserver: NSObject {
5360
)
5461
}
5562

56-
5763
private override init() {
5864
super.init()
5965
// Listen to Appearance Changes

Dynamic/Utilities/Preferences.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ extension Preferences {
5151
{ _, change in changeHandler(change) }
5252
}
5353
handles = [
54-
observe(\.adjustForBrightness, observeInitial: true) { change in
54+
observe(\.adjustForBrightness) { change in
5555
ScreenBrightnessObserver.shared.stop()
5656
if change.newValue == true {
5757
ScreenBrightnessObserver.shared.start()
5858
}
5959
},
60-
observe(\.scheduled, observeInitial: true) { change in
60+
observe(\.scheduled) { change in
6161
if change.newValue == true {
6262
Scheduler.shared.schedule()
6363
} else {

Dynamic/Utilities/Scheduler.swift

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ public final class Scheduler: NSObject, CLLocationManagerDelegate {
1616
public static let shared = Scheduler()
1717
private override init() { super.init() }
1818

19-
private var isScheduling = false
20-
public func schedule() {
21-
if isScheduling { return }
22-
isScheduling = true
19+
private func requestLocationUpdate() -> Bool {
2320
switch CLLocationManager.authorizationStatus() {
2421
case .authorizedAlways, .notDetermined:
2522
manager.stopUpdatingLocation()
@@ -28,79 +25,109 @@ public final class Scheduler: NSObject, CLLocationManagerDelegate {
2825
} else {
2926
manager.startUpdatingLocation()
3027
}
28+
return true
3129
default:
30+
return false
31+
}
32+
}
33+
34+
private var isScheduling = false
35+
public func schedule() {
36+
if isScheduling { return }
37+
isScheduling = true
38+
if !requestLocationUpdate() {
3239
scheduleAtCachedLocation()
3340
}
3441
}
3542

43+
public typealias StyleProcessor = (AppleInterfaceStyle?) -> Void
44+
private var _callback: StyleProcessor?
45+
private var callback: StyleProcessor? {
46+
get {
47+
defer { _callback = nil }
48+
return _callback
49+
}
50+
set {
51+
_callback = newValue
52+
}
53+
}
54+
public func getCurrentMode(then process: @escaping StyleProcessor) {
55+
callback = process
56+
if requestLocationUpdate() { return }
57+
callback?(nil)
58+
}
59+
3660
private var task: Task?
3761

38-
private func schedule(atLocation coordinate: CLLocationCoordinate2D?) {
39-
defer { isScheduling = false }
40-
guard preferences.scheduled else { return cancel() }
62+
public func mode(atLocation coordinate: CLLocationCoordinate2D?) -> (style: AppleInterfaceStyle, date: Date?) {
4163
let now = Date()
4264
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: now)!
4365
if let coordinate = coordinate
4466
, CLLocationCoordinate2DIsValid(coordinate)
4567
, preferences.scheduleZenithType != .custom {
46-
defer { removeAllNotifications() }
4768
let scheduledDate: Date
4869
let solar = Solar(for: now, coordinate: coordinate)!
4970
let dates = solar.sunriseSunsetTime
50-
#warning("FIXME: Having trouble figuring out time zone")
5171
if now < dates.sunrise {
52-
AppleInterfaceStyle.darkAqua.enable()
5372
scheduledDate = dates.sunrise
5473
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: now)!
5574
let pastSolar = Solar(for: yesterday, coordinate: coordinate)!
5675
preferences.scheduleStart = pastSolar.sunriseSunsetTime.sunset
5776
preferences.scheduleEnd = scheduledDate
77+
return (.darkAqua, scheduledDate)
5878
} else {
5979
let futureSolar = Solar(for: tomorrow, coordinate: coordinate)!
6080
let futureDates = futureSolar.sunriseSunsetTime
6181
if now < dates.sunset {
62-
AppleInterfaceStyle.aqua.enable()
6382
scheduledDate = dates.sunset
6483
preferences.scheduleStart = scheduledDate
6584
preferences.scheduleEnd = futureDates.sunrise
85+
return (.aqua, scheduledDate)
6686
} else { // after sunset
67-
AppleInterfaceStyle.darkAqua.enable()
6887
preferences.scheduleStart = dates.sunset
6988
scheduledDate = futureDates.sunrise
7089
preferences.scheduleEnd = scheduledDate
90+
return (.darkAqua, scheduledDate)
7191
}
7292
}
73-
return task = Plan.at(scheduledDate).do(onElapse: schedule)
7493
}
7594
if preferences.scheduleZenithType != .custom {
7695
preferences.scheduleZenithType = .custom
7796
}
78-
#warning("FIXME: This is gonna be a catastrophe when a user moves across timezone")
7997
let current = Calendar.current.dateComponents([.hour, .minute], from: now)
8098
let start = Calendar.current.dateComponents(
8199
[.hour, .minute], from: preferences.scheduleStart
82100
)
83101
let end = Calendar.current.dateComponents(
84102
[.hour, .minute], from: preferences.scheduleEnd
85103
)
86-
let scheduledDate: Date!
104+
if start == end { return (.current, nil) }
87105
if current < end {
88-
AppleInterfaceStyle.darkAqua.enable()
89-
scheduledDate = Calendar.current.date(
106+
return (.darkAqua, Calendar.current.date(
90107
bySettingHour: end.hour!, minute: end.minute!, second: 0, of: now
91-
)
108+
))
92109
} else if current < start {
93-
AppleInterfaceStyle.aqua.enable()
94-
scheduledDate = Calendar.current.date(
110+
return (.aqua, Calendar.current.date(
95111
bySettingHour: start.hour!, minute: start.minute!, second: 0, of: now
96-
)
97-
} else {
98-
AppleInterfaceStyle.darkAqua.enable()
99-
scheduledDate = Calendar.current.date(
112+
))
113+
} else if start > end {
114+
return (.darkAqua, Calendar.current.date(
100115
bySettingHour: end.hour!, minute: end.minute!, second: 0, of: tomorrow
101-
)
116+
))
117+
} else {
118+
return (.aqua, Calendar.current.date(
119+
bySettingHour: start.hour!, minute: start.minute!, second: 0, of: tomorrow
120+
))
102121
}
103-
task = Plan.at(scheduledDate).do(onElapse: schedule)
122+
}
123+
124+
private func schedule(atLocation coordinate: CLLocationCoordinate2D?) {
125+
defer { isScheduling = false }
126+
removeAllNotifications()
127+
let decision = mode(atLocation: coordinate)
128+
AppleScript.checkPermission(onSuccess: decision.style.enable)
129+
guard let date = decision.date else { return }
130+
task = Plan.at(date).do(onElapse: schedule)
104131
}
105132

106133
public func cancel() {
@@ -128,7 +155,12 @@ public final class Scheduler: NSObject, CLLocationManagerDelegate {
128155
guard let location = locations.last else { return }
129156
manager.stopUpdatingLocation()
130157
preferences.location = location
131-
schedule(atLocation: location.coordinate)
158+
let coordinate = location.coordinate
159+
if isScheduling {
160+
schedule(atLocation: coordinate)
161+
} else {
162+
callback?(mode(atLocation: coordinate).style)
163+
}
132164
}
133165

134166
public func locationManager(_ manager: CLLocationManager,

Dynamic/View Controller/AppDelegate.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,17 @@ func start() {
140140
started = true
141141
DispatchQueue.main.async {
142142
Preferences.setupObservers()
143-
AppleScript.checkPermission()
144143
_ = ScreenBrightnessObserver.shared
144+
AppleScript.checkPermission {
145+
DispatchQueue.main.async {
146+
Scheduler.shared.getCurrentMode {
147+
guard let style = $0
148+
?? ScreenBrightnessObserver.shared.mode
149+
else { return }
150+
style.enable()
151+
}
152+
}
153+
}
145154
}
146155
}
147156

0 commit comments

Comments
 (0)