From 3dfa624ca0ced66ab2ac6f536bb2e2ccd0f07b15 Mon Sep 17 00:00:00 2001 From: Jimmy Lu Date: Thu, 6 Apr 2017 13:30:19 -0700 Subject: [PATCH 1/6] add logging and some clean up of the animation code for night mode --- .../xcshareddata/xcschemes/Sense.xcscheme | 4 +- SleepModel/Base.lproj/Localizable.strings | 1 + SleepModel/NightModeService.swift | 2 +- SleepModel/NightModeSettingsPresenter.swift | 76 +++++++++++-------- 4 files changed, 50 insertions(+), 33 deletions(-) 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..a7e2c1cf 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 at this time. Try moving to a different location and try again."; "settings.units" = "Units and time"; "settings.support" = "Support"; "settings.tell-a-friend" = "Tell a friend about Sense"; 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..89a80435 100644 --- a/SleepModel/NightModeSettingsPresenter.swift +++ b/SleepModel/NightModeSettingsPresenter.swift @@ -143,6 +143,12 @@ 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) { @@ -152,29 +158,11 @@ class NightModeSettingsPresenter: HEMListPresenter { } } - 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,27 +178,55 @@ class NightModeSettingsPresenter: HEMListPresenter { } + fileprivate func requestLocationPermission() { + self.locationService.requestPermission({ (status: HEMLocationAuthStatus) in + self.waitingOnPermission = false + switch status { + case .notEnabled: + fallthrough + case .denied: + self.revertSelection(error: nil) + default: + self.scheduleNightModeFromLocation() + } + }) + } + + fileprivate func revertSelection(error: Error?) { + let savedOption = self.nightModeService.savedOption() + self.selectedItemNames = [savedOption.localizedDescription()] + self.tableView?.reloadData() // to disable the schedule cell + + if error != nil { + self.removeTransitionView(animate: false) + // 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) + } else { + self.removeTransitionView(animate: true) + } + } + 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() { var scheduled = false let service = self.locationService @@ -224,19 +240,19 @@ class NightModeSettingsPresenter: HEMListPresenter { if loc != nil { SENAnalytics.trackNightModeChange(withSetting: kHEMAnalyticsPropNightModeValueAuto) - self?.nightModeService.scheduleForSunset(latitude: Double(loc!.lat), - longitude: Double(loc!.lon)) + self?.nightModeService.scheduleForSunset(latitude: Double(loc!.lat), longitude: Double(loc!.lon)) self?.removeTransitionView(animate: true) + } else if err != nil { + self?.revertSelection(error: err) } else { - self?.removeTransitionView(animate: false) - self?.showLocationError() + SENAnalytics.trackWarning(withMessage: "could not determine location to schedule night mode") + self?.revertSelection(error: nil) } }) if error != nil { - self.removeTransitionView(animate: false) - self.showLocationError() + self.revertSelection(error: error) } } From 2e28c73f21b9c765d090c21a017940a923a36fd7 Mon Sep 17 00:00:00 2001 From: Jimmy Lu Date: Thu, 6 Apr 2017 13:31:12 -0700 Subject: [PATCH 2/6] bumping to 2.1.0.24 --- CHANGELOG.md | 4 ++++ Extensions/RoomConditions/Info.plist | 2 +- SleepModel/Sense-Info.plist | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5912f5c4..7dc12c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 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..092075ab 100644 --- a/Extensions/RoomConditions/Info.plist +++ b/Extensions/RoomConditions/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 2.1.0.23 + 2.1.0.24 NSExtension NSExtensionMainStoryboard diff --git a/SleepModel/Sense-Info.plist b/SleepModel/Sense-Info.plist index ee6b4a04..e549ae6d 100644 --- a/SleepModel/Sense-Info.plist +++ b/SleepModel/Sense-Info.plist @@ -35,7 +35,7 @@ CFBundleVersion - 2.1.0.23 + 2.1.0.24 FacebookAppID 372438546161587 FacebookDisplayName From 831d48183923919601aafa8511ec29542ac5effa Mon Sep 17 00:00:00 2001 From: Jimmy Lu Date: Thu, 6 Apr 2017 15:13:19 -0700 Subject: [PATCH 3/6] more testing changes --- SleepModel/Base.lproj/Localizable.strings | 2 +- SleepModel/NightModeSettingsPresenter.swift | 9 ++++----- SleepModel/Theme.swift | 16 ++++++++++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/SleepModel/Base.lproj/Localizable.strings b/SleepModel/Base.lproj/Localizable.strings index a7e2c1cf..16248e45 100644 --- a/SleepModel/Base.lproj/Localizable.strings +++ b/SleepModel/Base.lproj/Localizable.strings @@ -192,7 +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 at this time. Try moving to a different location and try again."; +"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/NightModeSettingsPresenter.swift b/SleepModel/NightModeSettingsPresenter.swift index 89a80435..7edc0187 100644 --- a/SleepModel/NightModeSettingsPresenter.swift +++ b/SleepModel/NightModeSettingsPresenter.swift @@ -155,6 +155,7 @@ class NightModeSettingsPresenter: HEMListPresenter { snapshot.frame = self.activityContainerView!.bounds self.activityContainerView!.addSubview(snapshot) self.transitionView = snapshot + // the transitionView will be removed when the theme is changed, in didChange: } } @@ -197,14 +198,13 @@ class NightModeSettingsPresenter: HEMListPresenter { self.selectedItemNames = [savedOption.localizedDescription()] self.tableView?.reloadData() // to disable the schedule cell + self.removeTransitionView(animate: true) + if error != nil { - self.removeTransitionView(animate: false) // 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) - } else { - self.removeTransitionView(animate: true) } } @@ -235,7 +235,7 @@ class NightModeSettingsPresenter: HEMListPresenter { guard scheduled == false else { return } - + scheduled = true if loc != nil { @@ -245,7 +245,6 @@ class NightModeSettingsPresenter: HEMListPresenter { } else if err != nil { self?.revertSelection(error: err) } else { - SENAnalytics.trackWarning(withMessage: "could not determine location to schedule night mode") self?.revertSelection(error: nil) } diff --git a/SleepModel/Theme.swift b/SleepModel/Theme.swift index 1cab7874..f4039889 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,19 @@ 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 + print("calling viewcontrollers of nav,", NSStringFromClass(type(of: navVC))) 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 + print("calling viewcontrollers of tab,", NSStringFromClass(type(of: tabVC))) self.apply(viewController: tabController, auto: auto) }) } @@ -314,9 +319,12 @@ import UIKit return } + print("notifying controller,", NSStringFromClass(type(of: controller))) 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) + } } } From 8dbed9a53bcf4ca4371079d603ce3a55fdfe0049 Mon Sep 17 00:00:00 2001 From: Jimmy Lu Date: Thu, 6 Apr 2017 15:14:45 -0700 Subject: [PATCH 4/6] bumping to 2.1.0.25 --- CHANGELOG.md | 7 +++++++ Extensions/RoomConditions/Info.plist | 2 +- SleepModel/Sense-Info.plist | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dc12c73..55128753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 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 diff --git a/Extensions/RoomConditions/Info.plist b/Extensions/RoomConditions/Info.plist index 092075ab..6c67d735 100644 --- a/Extensions/RoomConditions/Info.plist +++ b/Extensions/RoomConditions/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 2.1.0.24 + 2.1.0.25 NSExtension NSExtensionMainStoryboard diff --git a/SleepModel/Sense-Info.plist b/SleepModel/Sense-Info.plist index e549ae6d..aedba92d 100644 --- a/SleepModel/Sense-Info.plist +++ b/SleepModel/Sense-Info.plist @@ -35,7 +35,7 @@ CFBundleVersion - 2.1.0.24 + 2.1.0.25 FacebookAppID 372438546161587 FacebookDisplayName From 0aa56922841ba812dac1a505ab871c05214e2600 Mon Sep 17 00:00:00 2001 From: Jimmy Lu Date: Thu, 6 Apr 2017 16:11:02 -0700 Subject: [PATCH 5/6] request location until something good comes before remove transition view --- SleepModel/HEMLocationService.h | 3 +- SleepModel/HEMLocationService.m | 4 + SleepModel/NightModeSettingsPresenter.swift | 92 +++++++++++++-------- SleepModel/Theme.swift | 3 - 4 files changed, 65 insertions(+), 37 deletions(-) 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/NightModeSettingsPresenter.swift b/SleepModel/NightModeSettingsPresenter.swift index 7edc0187..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) @@ -183,24 +189,24 @@ class NightModeSettingsPresenter: HEMListPresenter { self.locationService.requestPermission({ (status: HEMLocationAuthStatus) in self.waitingOnPermission = false switch status { - case .notEnabled: - fallthrough - case .denied: - self.revertSelection(error: nil) - default: - self.scheduleNightModeFromLocation() + case .notEnabled: + fallthrough + case .denied: + self.revertSelection(withError: false) + default: + self.scheduleNightModeFromLocation() } }) } - fileprivate func revertSelection(error: Error?) { + 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 error != nil { + 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") @@ -228,31 +234,51 @@ class NightModeSettingsPresenter: HEMListPresenter { } 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 if err != nil { - self?.revertSelection(error: err) - } else { - self?.revertSelection(error: nil) - } - - }) + guard let service = self.locationService else { + self.revertSelection(withError: false) + return + } - if error != nil { - self.revertSelection(error: error) + 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) + } + } + + deinit { + guard let service = self.locationService else { + return } + + guard let activity = self.locationActivity else { + return + } + + service.stop(activity) } } diff --git a/SleepModel/Theme.swift b/SleepModel/Theme.swift index f4039889..8f059d2c 100644 --- a/SleepModel/Theme.swift +++ b/SleepModel/Theme.swift @@ -302,7 +302,6 @@ import UIKit if let navVC = controller as? UINavigationController { viewControllers = navVC.viewControllers viewControllers?.forEach({ (controllerInStack: UIViewController) in - print("calling viewcontrollers of nav,", NSStringFromClass(type(of: navVC))) self.apply(viewController: controllerInStack, auto: auto) }) } @@ -310,7 +309,6 @@ import UIKit if let tabVC = controller as? UITabBarController { viewControllers = tabVC.viewControllers viewControllers?.forEach({ (tabController: UIViewController) in - print("calling viewcontrollers of tab,", NSStringFromClass(type(of: tabVC))) self.apply(viewController: tabController, auto: auto) }) } @@ -319,7 +317,6 @@ import UIKit return } - print("notifying controller,", NSStringFromClass(type(of: controller))) themedVC.didChange(theme: self, auto: auto) controller.childViewControllers.forEach { (child: UIViewController) in if viewControllers == nil || viewControllers!.contains(child) == false { From 27bdc80a79cd2f8ff4f6cbabc7fb144d7222fc90 Mon Sep 17 00:00:00 2001 From: Jimmy Lu Date: Thu, 6 Apr 2017 16:12:08 -0700 Subject: [PATCH 6/6] bumping to 2.1.0.26 --- CHANGELOG.md | 6 ++++++ Extensions/RoomConditions/Info.plist | 2 +- SleepModel/Sense-Info.plist | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55128753..fb1bfb02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 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: diff --git a/Extensions/RoomConditions/Info.plist b/Extensions/RoomConditions/Info.plist index 6c67d735..e68a0020 100644 --- a/Extensions/RoomConditions/Info.plist +++ b/Extensions/RoomConditions/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 2.1.0.25 + 2.1.0.26 NSExtension NSExtensionMainStoryboard diff --git a/SleepModel/Sense-Info.plist b/SleepModel/Sense-Info.plist index aedba92d..a27e4f7b 100644 --- a/SleepModel/Sense-Info.plist +++ b/SleepModel/Sense-Info.plist @@ -35,7 +35,7 @@ CFBundleVersion - 2.1.0.25 + 2.1.0.26 FacebookAppID 372438546161587 FacebookDisplayName