diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5912f5c4..fb1bfb02 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,22 @@
# Changelog
+## 2.1.0.26
+
+Fixes:
+
+* Another attempt to fix night mode transition by requesting more than 1 location objects, until 1 is valid
+
+## 2.1.0.25
+
+Fixes:
+
+* Prevent multiple calls to update theme
+* Update error message
+
+## 2.1.0.24
+
+* Adding additional logging for Night Mode to see why animation is disabled on schedule
+
## 2.1.0.23
Fixes:
diff --git a/Extensions/RoomConditions/Info.plist b/Extensions/RoomConditions/Info.plist
index 4225e5a6..e68a0020 100644
--- a/Extensions/RoomConditions/Info.plist
+++ b/Extensions/RoomConditions/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 2.1.0.23
+ 2.1.0.26
NSExtension
NSExtensionMainStoryboard
diff --git a/Sense.xcodeproj/xcshareddata/xcschemes/Sense.xcscheme b/Sense.xcodeproj/xcshareddata/xcschemes/Sense.xcscheme
index 4777fde1..4e4ab964 100644
--- a/Sense.xcodeproj/xcshareddata/xcschemes/Sense.xcscheme
+++ b/Sense.xcodeproj/xcshareddata/xcschemes/Sense.xcscheme
@@ -75,12 +75,12 @@
+ isEnabled = "NO">
+ isEnabled = "NO">
diff --git a/SleepModel/Base.lproj/Localizable.strings b/SleepModel/Base.lproj/Localizable.strings
index 4dd231eb..16248e45 100644
--- a/SleepModel/Base.lproj/Localizable.strings
+++ b/SleepModel/Base.lproj/Localizable.strings
@@ -192,6 +192,7 @@
"settings.night-mode.option.scheduled.description" = "Automatic from sunset to sunrise.";
"settings.night-mode.no-location.message.format" = "%@ must be enabled for Sense to know local sunset and sunrise times.";
"settings.night-mode.location.service" = "Location Services";
+"settings.night-mode.error.no-location" = "Your location could not be determined. Make sure Location Service is enabled or try moving to a different location.";
"settings.units" = "Units and time";
"settings.support" = "Support";
"settings.tell-a-friend" = "Tell a friend about Sense";
diff --git a/SleepModel/HEMLocationService.h b/SleepModel/HEMLocationService.h
index 2dea68f9..c5f828ba 100644
--- a/SleepModel/HEMLocationService.h
+++ b/SleepModel/HEMLocationService.h
@@ -46,7 +46,8 @@ typedef void(^HEMLocationHandler)(HEMLocation* _Nullable mostRecentLocation, NSE
- (HEMLocationAuthStatus)authorizationStatus;
- (BOOL)requiresPermission;
- (BOOL)hasDeniedPermission;
-- (NSError*)quickLocation:(HEMLocationHandler)completion;
+- (BOOL)isEnabled;
+- (nullable NSError*)quickLocation:(HEMLocationHandler)completion;
- (void)requestPermission:(HEMLocationAuthorizationHandler)authHandler;
- (nullable HEMLocationActivity*)startLocationActivity:(HEMLocationHandler)update
error:(NSError**)error;
diff --git a/SleepModel/HEMLocationService.m b/SleepModel/HEMLocationService.m
index a07c78d7..10fe7dce 100644
--- a/SleepModel/HEMLocationService.m
+++ b/SleepModel/HEMLocationService.m
@@ -102,6 +102,10 @@ - (HEMLocationAuthStatus)authorizationStatus {
return HEMLocationAuthStatusAuthorized;
}
}
+
+- (BOOL)isEnabled {
+ return [CLLocationManager locationServicesEnabled];
+}
- (BOOL)hasDeniedPermission {
return [self authorizationStatus] == HEMLocationAuthStatusDenied;
diff --git a/SleepModel/NightModeService.swift b/SleepModel/NightModeService.swift
index 4901b9ee..924163ce 100644
--- a/SleepModel/NightModeService.swift
+++ b/SleepModel/NightModeService.swift
@@ -148,7 +148,7 @@ class NightModeService: SENService {
func scheduleForSunset(latitude: Double, longitude: Double) {
self.updateLocation(latitude: latitude, longitude: longitude)
self.save(option: .sunsetToSunrise)
- }
+ }
@objc func updateLocation(latitude: Double, longitude: Double) {
let latKey = NightModeService.settingsLatKey
diff --git a/SleepModel/NightModeSettingsPresenter.swift b/SleepModel/NightModeSettingsPresenter.swift
index b14c24db..98004edd 100644
--- a/SleepModel/NightModeSettingsPresenter.swift
+++ b/SleepModel/NightModeSettingsPresenter.swift
@@ -17,6 +17,7 @@ class NightModeSettingsPresenter: HEMListPresenter {
fileprivate var footer: UIView?
fileprivate var waitingOnPermission: Bool
fileprivate weak var transitionView: UIView?
+ fileprivate var locationActivity: HEMLocationActivity?
init(nightModeService: NightModeService, locationService: HEMLocationService) {
let optionsTitle = NSLocalizedString("settings.night-mode.options.title", comment: "table options title")
@@ -74,9 +75,12 @@ class NightModeSettingsPresenter: HEMListPresenter {
textView.isScrollEnabled = false
textView.backgroundColor = self.tableView!.backgroundColor
+ let enabled = self.locationService.isEnabled()
+ let denied = self.locationService.hasDeniedPermission()
+
let footer = UIView()
footer.addSubview(textView)
- footer.isHidden = self.locationService.hasDeniedPermission() == false
+ footer.isHidden = denied == false && enabled == true
return footer
}
@@ -134,7 +138,9 @@ class NightModeSettingsPresenter: HEMListPresenter {
cell.descriptionLabel?.text = self.detail(forItem: item)
if option == .sunsetToSunrise {
- self.footer?.isHidden = self.locationService.hasDeniedPermission() == false
+ let enabled = self.locationService.isEnabled()
+ let denied = self.locationService.hasDeniedPermission()
+ self.footer?.isHidden = denied == false && enabled == true
cell.enable(self.footer?.isHidden == true)
} else {
cell.enable(true)
@@ -143,38 +149,27 @@ class NightModeSettingsPresenter: HEMListPresenter {
override func didNotifyDelegateOfSelection() {
super.didNotifyDelegateOfSelection()
+
+ let selectedName = self.selectedItemNames?.last as? String ?? ""
+ guard let option = NightModeService.Option.fromDescription(description: selectedName) else {
+ return
+ }
+
// snapshot the screen
if self.activityContainerView != nil {
if let snapshot = self.activityContainerView!.snapshotView(afterScreenUpdates: false) {
snapshot.frame = self.activityContainerView!.bounds
self.activityContainerView!.addSubview(snapshot)
self.transitionView = snapshot
+ // the transitionView will be removed when the theme is changed, in didChange:
}
}
- let selectedName = self.selectedItemNames?.last as? String ?? ""
- guard let option = NightModeService.Option.fromDescription(description: selectedName) else {
- return
- }
-
switch option {
case .sunsetToSunrise:
if self.locationService.requiresPermission() == true {
self.waitingOnPermission = true
- self.locationService.requestPermission({ (status: HEMLocationAuthStatus) in
- self.waitingOnPermission = false
- switch status {
- case .notEnabled:
- fallthrough
- case .denied:
- let savedOption = self.nightModeService.savedOption()
- self.selectedItemNames = [savedOption.localizedDescription()]
- self.tableView?.reloadData() // to disable the schedule cell
- self.removeTransitionView(animate: false)
- default:
- self.scheduleNightModeFromLocation()
- }
- })
+ self.requestLocationPermission()
} else {
self.scheduleNightModeFromLocation()
}
@@ -190,54 +185,100 @@ class NightModeSettingsPresenter: HEMListPresenter {
}
+ fileprivate func requestLocationPermission() {
+ self.locationService.requestPermission({ (status: HEMLocationAuthStatus) in
+ self.waitingOnPermission = false
+ switch status {
+ case .notEnabled:
+ fallthrough
+ case .denied:
+ self.revertSelection(withError: false)
+ default:
+ self.scheduleNightModeFromLocation()
+ }
+ })
+ }
+
+ fileprivate func revertSelection(withError: Bool) {
+ let savedOption = self.nightModeService.savedOption()
+ self.selectedItemNames = [savedOption.localizedDescription()]
+ self.tableView?.reloadData() // to disable the schedule cell
+
+ self.removeTransitionView(animate: true)
+
+ if withError == true {
+ // show error
+ let title = NSLocalizedString("settings.night-mode", comment: "title, same as screen title")
+ let message = NSLocalizedString("settings.night-mode.error.no-location", comment: "no location error")
+ self.presenterDelegate?.presentError(withTitle: title, message: message, from: self)
+ }
+ }
+
fileprivate func removeTransitionView(animate: Bool) {
guard let view = self.transitionView else {
+ SENAnalytics.trackWarning(withMessage: "snapshot already removed in night mode settings")
return
}
guard animate == true else {
+ SENAnalytics.trackWarning(withMessage: "animation disabled when removing snapshot in night mode settings")
view.removeFromSuperview()
return
}
- UIView.animate(withDuration: 0.35, animations: {
+ UIView.animate(withDuration: 0.35, delay: 0.0, options: .beginFromCurrentState, animations: {
view.alpha = 0.0
}) { (finished: Bool) in
view.removeFromSuperview()
}
}
- fileprivate func showLocationError() {
- // TODO: throw an alert
+ fileprivate func scheduleNightModeFromLocation() {
+ guard let service = self.locationService else {
+ self.revertSelection(withError: false)
+ return
+ }
+
+ var done = false
+ do {
+ self.locationActivity = try service.startLocationActivity({ [weak self] (loc: HEMLocation?, err: Error?) in
+ // to ensure only 1 location is used and to not call it too many times
+ guard done == false else {
+ return
+ }
+
+ if loc != nil {
+ done = true
+ SENAnalytics.trackNightModeChange(withSetting: kHEMAnalyticsPropNightModeValueAuto)
+ self?.nightModeService.scheduleForSunset(latitude: Double(loc!.lat), longitude: Double(loc!.lon))
+ self?.removeTransitionView(animate: true)
+ } else if err != nil {
+ done = true
+ self?.revertSelection(withError: true)
+ }
+
+ if done == true {
+ if let activity = self?.locationActivity, let locService = self?.locationService {
+ locService.stop(activity)
+ }
+ }
+
+ })
+ } catch _ {
+ self.revertSelection(withError: true)
+ }
}
- fileprivate func scheduleNightModeFromLocation() {
- var scheduled = false
- let service = self.locationService
- let error = service?.quickLocation({[weak self] (loc: HEMLocation?, err: Error?) in
- // to ensure only 1 location is used and to not call it too many times
- guard scheduled == false else {
- return
- }
-
- scheduled = true
-
- if loc != nil {
- SENAnalytics.trackNightModeChange(withSetting: kHEMAnalyticsPropNightModeValueAuto)
- self?.nightModeService.scheduleForSunset(latitude: Double(loc!.lat),
- longitude: Double(loc!.lon))
- self?.removeTransitionView(animate: true)
- } else {
- self?.removeTransitionView(animate: false)
- self?.showLocationError()
- }
-
- })
+ deinit {
+ guard let service = self.locationService else {
+ return
+ }
- if error != nil {
- self.removeTransitionView(animate: false)
- self.showLocationError()
+ guard let activity = self.locationActivity else {
+ return
}
+
+ service.stop(activity)
}
}
diff --git a/SleepModel/Sense-Info.plist b/SleepModel/Sense-Info.plist
index ee6b4a04..a27e4f7b 100644
--- a/SleepModel/Sense-Info.plist
+++ b/SleepModel/Sense-Info.plist
@@ -35,7 +35,7 @@
CFBundleVersion
- 2.1.0.23
+ 2.1.0.26
FacebookAppID
372438546161587
FacebookDisplayName
diff --git a/SleepModel/Theme.swift b/SleepModel/Theme.swift
index 1cab7874..8f059d2c 100644
--- a/SleepModel/Theme.swift
+++ b/SleepModel/Theme.swift
@@ -220,8 +220,8 @@ import UIKit
let app = UIApplication.shared
let keyWindow = app.delegate?.window
let rootVC = keyWindow??.rootViewController
- self.apply(viewController: rootVC, auto: auto)
self.applyApearances()
+ self.apply(viewController: rootVC, auto: auto)
}
fileprivate func applyApearances() {
@@ -298,14 +298,17 @@ import UIKit
return
}
+ var viewControllers: [UIViewController]?
if let navVC = controller as? UINavigationController {
- navVC.viewControllers.forEach({ (controllerInStack: UIViewController) in
+ viewControllers = navVC.viewControllers
+ viewControllers?.forEach({ (controllerInStack: UIViewController) in
self.apply(viewController: controllerInStack, auto: auto)
})
}
if let tabVC = controller as? UITabBarController {
- tabVC.viewControllers?.forEach({ (tabController: UIViewController) in
+ viewControllers = tabVC.viewControllers
+ viewControllers?.forEach({ (tabController: UIViewController) in
self.apply(viewController: tabController, auto: auto)
})
}
@@ -316,7 +319,9 @@ import UIKit
themedVC.didChange(theme: self, auto: auto)
controller.childViewControllers.forEach { (child: UIViewController) in
- self.apply(viewController: child, auto: auto)
+ if viewControllers == nil || viewControllers!.contains(child) == false {
+ self.apply(viewController: child, auto: auto)
+ }
}
}