Commit 6951589f by Dmitriy Stepanets

Merge branch 'release/5.3' into develop

# Conflicts:
#	OneWeatherAnalytics/OneWeatherAnalytics/AnalyticsEvent.swift
#	OneWeatherCore/OneWeatherCore/Managers/WidgetManager.swift
#	OneWeatherCore/OneWeatherCore/Settings/Settings.swift
parents f7988497 1d41afe7
......@@ -80,7 +80,7 @@
<EnvironmentVariables>
<EnvironmentVariable
key = "_XCWidgetKind"
value = "com.onelouder.oneweather.widget.radar"
value = "com.onelouder.oneweather.widget.temperature"
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
......@@ -90,7 +90,7 @@
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetFamily"
value = "large"
value = "medium"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
......
......@@ -35,6 +35,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
ThemeManager.refreshAppearance()
UserDefaults.migrateUserDefaultsToAppGroupsIfNeeded()
if let launchOptions = launchOptions {
log.debug("Launch options: \(launchOptions)")
......
......@@ -51,7 +51,7 @@ class CCPAHelper {
locationPermissionsUndeterminedOnLaunch && !hadLocationsOnLaunch
}
@UserDefaultsOptionalValue("CCPAHelper.canCollectData")
@UserDefaultsOptionalValue("CCPAHelper.canCollectData", userDefaults: UserDefaults.appDefaults)
public var canCollectData: Bool?
private var locationPermissionsUndeterminedOnLaunch: Bool = false
......@@ -70,7 +70,7 @@ class CCPAHelper {
private static let statusUpdateDelayAfterRegistration: TimeInterval = 5
private static let defaultMinimumTimeSinceLastSuccessfulUpdate: TimeInterval = 3600 * 24 * 7 // a week
@UserDefaultsValue("CCPAHelper.shownPrivacyNoticeBefore", defaultValue: false)
@UserDefaultsValue("CCPAHelper.shownPrivacyNoticeBefore", defaultValue: false, userDefaults: UserDefaults.appDefaults)
public var shownPrivacyNoticeBefore: Bool {
didSet {
if shownPrivacyNoticeBefore {
......@@ -79,7 +79,7 @@ class CCPAHelper {
}
}
@UserDefaultsValue("CCPAHelper.policyHasBeenUpdated", defaultValue: false)
@UserDefaultsValue("CCPAHelper.policyHasBeenUpdated", defaultValue: false, userDefaults: UserDefaults.appDefaults)
public private(set) var policyHasBeenUpdated: Bool {
didSet {
if policyHasBeenUpdated {
......@@ -88,18 +88,18 @@ class CCPAHelper {
}
}
@UserDefaultsOptionalValue("CCPAHelper.lastSeenPrivacyPolicyVersion")
@UserDefaultsOptionalValue("CCPAHelper.lastSeenPrivacyPolicyVersion", userDefaults: UserDefaults.appDefaults)
public var lastSeenPrivacyPolicyVersion: Int?
private let log = Logger(componentName: "CCPAHelper")
@UserDefaultsValue("CCPAHelper.isRegistered", defaultValue: false)
@UserDefaultsValue("CCPAHelper.isRegistered", defaultValue: false, userDefaults: UserDefaults.appDefaults)
private var isRegistered: Bool
@UserDefaultsOptionalValue("CCPAHelper.privacyString")
@UserDefaultsOptionalValue("CCPAHelper.privacyString", userDefaults: UserDefaults.appDefaults)
private var privacyString: String?
@UserDefaultsOptionalValue("CCPAHelper.lastUpdateCallData")
@UserDefaultsOptionalValue("CCPAHelper.lastUpdateCallData", userDefaults: UserDefaults.appDefaults)
private var lastSuccessfullUpdateDate: Date?
private var minimumTimeSinceLastSuccessfulUpdate: TimeInterval {
......
......@@ -26,7 +26,7 @@ class PromotionPresentationAnimator: NSObject, UIViewControllerAnimatedTransitio
height: contentHeight)
container.addSubview(toViewController.view)
UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
toViewController.view.frame.origin.y = container.frame.height - contentHeight
toViewController.view.frame.origin.y = container.bounds.height * 0.46
} completion: { finished in
transitionContext.completeTransition(finished)
}
......
......@@ -79,7 +79,7 @@ private extension PromotionSmallWidgetView {
func prepareTopLabel() {
let select = "widget.promotion.selectList".localized()
let widgets = "16 \("widget.promotion.widgets".localized())"
let widgets = "7 \("widget.promotion.widgets".localized())"
let attrString = NSMutableAttributedString(string: select + "\n" + widgets)
attrString.addAttribute(.font,
......
......@@ -20,12 +20,8 @@ class WidgetPromotionController: UIViewController {
private let stackView = UIStackView()
private let footerView = UIView()
private let learnButton = UIButton()
private var initialTouchPoint = CGPoint(x: 0,y: 0)
private lazy var panGesture: UIPanGestureRecognizer = {
let gesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(sender:)))
gesture.delegate = self
return gesture
}()
private let fullView: CGFloat = UIScreen.main.bounds.height - UIScreen.main.bounds.height * 0.9
private let partialView: CGFloat = UIScreen.main.bounds.height * 0.46
//Public
var controllerContentHeight: CGFloat {
......@@ -60,10 +56,6 @@ class WidgetPromotionController: UIViewController {
updateUI()
AppAnalytics.shared.log(event: .ANALYTICS_WIDGET_PROMO_SEEN)
#warning("--LOOK-")
//In this version the promo controller opens fully everytime
AppAnalytics.shared.log(event: .ANALYTICS_WIDGET_PROMO_EXPAND)
}
override func viewDidAppear(_ animated: Bool) {
......@@ -99,26 +91,33 @@ class WidgetPromotionController: UIViewController {
}
}
@objc private func handlePanGesture(sender: UIPanGestureRecognizer) {
let touchPoint = sender.location(in: self.view?.window)
let originalOffsetY = UIScreen.main.bounds.height - self.view.bounds.height
switch sender.state {
case .began:
initialTouchPoint = touchPoint
@objc private func handlePanGesture(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.view)
let velocity = recognizer.velocity(in: self.view)
let y = self.view.frame.minY
switch recognizer.state {
case .changed:
if touchPoint.y - initialTouchPoint.y > 0 {
view.frame.origin.y = originalOffsetY + (touchPoint.y - initialTouchPoint.y)
self.view.frame = CGRect(x: 0, y: y + translation.y, width: view.frame.width, height: view.frame.height)
recognizer.setTranslation(CGPoint.zero, in: self.view)
case .ended:
var duration = velocity.y < 0 ? Double((y - fullView) / -velocity.y) : Double((partialView - y) / velocity.y )
duration = duration > 0.3 ? 0.3 : duration
if velocity.y >= 0 {
self.close()
}
case .cancelled, .ended:
if touchPoint.y - initialTouchPoint.y > 80 {
close()
} else {
UIView.animate(withDuration: 0.25, animations: {
self.view.frame.origin.y = originalOffsetY
})
else {
UIView.animate(withDuration: duration) {
self.view.frame = CGRect(x: 0, y: self.fullView, width: self.view.frame.width, height: self.view.frame.height)
} completion: {[weak self] _ in
if ( velocity.y < 0 ) {
self?.scrollView.isScrollEnabled = true
AppAnalytics.shared.log(event: .ANALYTICS_WIDGET_PROMO_EXPAND)
}
}
}
break
default:
break
}
......@@ -141,7 +140,9 @@ class WidgetPromotionController: UIViewController {
@available(iOS 14, *)
private extension WidgetPromotionController {
func prepareView() {
// view.addGestureRecognizer(panGesture)
let gesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(recognizer:)))
gesture.delegate = self
view.addGestureRecognizer(gesture)
view.clipsToBounds = true
view.layer.cornerRadius = 24
......@@ -199,9 +200,9 @@ private extension WidgetPromotionController {
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .temperatureMedium))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .temperatureLarge))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .precipitationMedium))
// stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .windMedium))
// stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .windLarge))
// stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .radarLarge))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .windMedium))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .windLarge))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .radarLarge))
scrollView.addSubview(stackView)
stackView.snp.makeConstraints { make in
......@@ -260,11 +261,6 @@ extension WidgetPromotionController: UIScrollViewDelegate {
if scrollView.contentOffset.y == scrollView.contentSize.height - scrollView.frame.height {
AppAnalytics.shared.log(event: .ANALYTICS_WIDGET_BOTTOM_SCROLLED)
}
// if scrollView.contentOffset.y < 0 {
// let originalOffsetY = UIScreen.main.bounds.height - self.view.bounds.height
// view.frame.origin.y = originalOffsetY - (scrollView.contentOffset.y - initialTouchPoint.y)
// return
// }
}
}
......@@ -272,27 +268,17 @@ extension WidgetPromotionController: UIScrollViewDelegate {
//MARK:- UIGesture Delegate
@available(iOS 14, *)
extension WidgetPromotionController: UIGestureRecognizerDelegate {
// func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// if scrollView.contentOffset.y > 0 {
// return false
// }
//
// scrollView.contentOffset.y = 0
// return true
// }
// func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
// shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// // Do not begin the pan until the swipe fails.
// if otherGestureRecognizer != self.panGesture {
// print("ScrollView Offset \(scrollView.contentOffset.y)")
// if scrollView.contentOffset.y >= 0 {
// return false
// }
//
// return true
// }
//
// return false
// }
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
let gesture = (gestureRecognizer as! UIPanGestureRecognizer)
let direction = gesture.velocity(in: view).y
let y = view.frame.minY
if (y == fullView && scrollView.contentOffset.y == 0 && direction > 0) || (y == partialView) {
scrollView.isScrollEnabled = false
} else {
scrollView.isScrollEnabled = true
}
return false
}
}
......@@ -94,7 +94,6 @@ public enum AnalyticsEvent: String {
case ANALYTICS_WIDGET_PROMO_EXPAND = "WIDGET_PROMO_EXPAND"
case ANALYTICS_WIDGET_BOTTOM_SCROLLED = "WIDGET_PROMO_BOTTOM_SCROLLED"
case ANALYTICS_WIDGET_PROMO_LEARN_CTA = "WIDGET_PROMO_LEARN_CTA"
case ANALYTICS_WIDGET_LAUNCH_FROM = "LAUNCH_FROM_WIDGET"
///Widget actions
case ANALYTICS_WIDGET_PLACED = "WIDGET_PLACED"
......
......@@ -23,6 +23,7 @@ public enum AnalyticsParameter: String {
case ANALYTICS_KEY_FIRST_OPEN_SOURCE = "Source"
case ANALYTICS_KEY_FIRST_OPEN_FLOW = "Flow"
case ANALYTICS_KEY_WIDGET_NAME = "widget_name"
case ANALYTICS_KEY_WIDGET_SMART_TEXT = "smart_text"
case ANALYTICS_KEY_SHORTS_CARD_POSITION = "position"
case ANALYTICS_KEY_SHORTS_CARD_ID = "card_id"
case ANALYTICS_KEY_SHORTS_TIME_SPENT = "time_spent"
......
......@@ -77,6 +77,7 @@
CDFE458D26566BD50021A29F /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDFE458C26566BD50021A29F /* Storage.swift */; };
CDFE459426566D7B0021A29F /* HealthSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDFE459326566D7B0021A29F /* HealthSource.swift */; };
CDFE459626566D860021A29F /* FIPSSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDFE459526566D860021A29F /* FIPSSource.swift */; };
CE3A112726CD3CDE00D925C7 /* UserDefaults+OneWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3A112626CD3CDE00D925C7 /* UserDefaults+OneWeather.swift */; };
CEFE851826948C15003C67D3 /* SmartTextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851726948C15003C67D3 /* SmartTextProvider.swift */; };
CEFE851C2694986D003C67D3 /* SmartText.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851B2694986D003C67D3 /* SmartText.swift */; };
CEFE85202694C4BC003C67D3 /* DefaultSmartText.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851F2694C4BC003C67D3 /* DefaultSmartText.swift */; };
......@@ -176,6 +177,7 @@
CDFE458C26566BD50021A29F /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
CDFE459326566D7B0021A29F /* HealthSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthSource.swift; sourceTree = "<group>"; };
CDFE459526566D860021A29F /* FIPSSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FIPSSource.swift; sourceTree = "<group>"; };
CE3A112626CD3CDE00D925C7 /* UserDefaults+OneWeather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+OneWeather.swift"; sourceTree = "<group>"; };
CEFE851726948C15003C67D3 /* SmartTextProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextProvider.swift; sourceTree = "<group>"; };
CEFE851B2694986D003C67D3 /* SmartText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartText.swift; sourceTree = "<group>"; };
CEFE851D2694C477003C67D3 /* SmartTextMacro.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextMacro.swift; sourceTree = "<group>"; };
......@@ -378,6 +380,7 @@
CD615FB22655293100B717DB /* CLAuthorizationStatus+Localized.swift */,
CD615FB32655293100B717DB /* UIApplication+Settings.swift */,
CD71B9C5265E629D00803DBB /* String+NewLine.swift */,
CE3A112626CD3CDE00D925C7 /* UserDefaults+OneWeather.swift */,
);
path = Extensions;
sourceTree = "<group>";
......@@ -673,6 +676,7 @@
CD427D19266F5DCE00B4350A /* ShortsSource.swift in Sources */,
CD2D55D8265533F4007B70F4 /* UserDefaultsWrapper.swift in Sources */,
CDD2F8F62665117400B48322 /* NWSAlertsManager.swift in Sources */,
CE3A112726CD3CDE00D925C7 /* UserDefaults+OneWeather.swift in Sources */,
CD11AFE726651BF900EC4BA0 /* LegacyWdtLocation.swift in Sources */,
CD11AFE326651B6300EC4BA0 /* LegacyMigrationManager.swift in Sources */,
CD2D55DD2655377F007B70F4 /* NWSAlertExtendedInfo.swift in Sources */,
......
......@@ -11,18 +11,20 @@ import Foundation
@propertyWrapper
public struct UserDefaultsOptionalValue<T> {
public let key: String
private let userDefaults: UserDefaults
public init(_ key: String) {
public init(_ key: String, userDefaults: UserDefaults) {
self.key = key
self.userDefaults = userDefaults
}
public var wrappedValue: T? {
get {
return UserDefaults.standard.object(forKey: key) as? T
return userDefaults.object(forKey: key) as? T
}
set {
UserDefaults.standard.set(newValue, forKey: key)
UserDefaults.standard.synchronize()
userDefaults.set(newValue, forKey: key)
userDefaults.synchronize()
}
}
}
......@@ -12,19 +12,21 @@ import Foundation
public struct UserDefaultsValue<T> {
public let key: String
public let defaultValue: T
private let userDefaults: UserDefaults
public init(_ key: String, defaultValue: T) {
public init(_ key: String, defaultValue: T, userDefaults: UserDefaults) {
self.key = key
self.defaultValue = defaultValue
self.userDefaults = userDefaults
}
public var wrappedValue: T {
get {
return (UserDefaults.standard.object(forKey: key) as? T) ?? defaultValue
return (userDefaults.object(forKey: key) as? T) ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
UserDefaults.standard.synchronize()
userDefaults.set(newValue, forKey: key)
userDefaults.synchronize()
}
}
}
......@@ -6,9 +6,21 @@
//
import Foundation
import WidgetKit
@propertyWrapper
public struct UserDefaultsUnitValue<T> {
private let key: String
private let defaultValue: T
private var lastKnownValue: T?
private let userDefaults: UserDefaults
public init(wrappedValue defaultValue:T, key:String, userDefaults: UserDefaults) {
self.defaultValue = defaultValue
self.key = key
self.userDefaults = userDefaults
}
public var wrappedValue: T {
get {
// TODO: If we will ever have 2 instances of UserDefaultsUnitValue with the same key at the same time, this cache will become desynchronized.
......@@ -16,7 +28,7 @@ public struct UserDefaultsUnitValue<T> {
return knownValue
}
guard
let data = UserDefaults.standard.data(forKey: key),
let data = userDefaults.data(forKey: key),
let decoded = NSKeyedUnarchiver.unarchiveObject(with: data) as? T
else {
return defaultValue
......@@ -27,46 +39,46 @@ public struct UserDefaultsUnitValue<T> {
set {
lastKnownValue = newValue
let data = NSKeyedArchiver.archivedData(withRootObject: newValue)
UserDefaults.standard.set(data, forKey: key)
UserDefaults.standard.synchronize()
userDefaults.set(data, forKey: key)
Settings.shared.delegate.invoke { (delegate) in
delegate.settingsDidChange()
}
if #available(iOS 14, *) {
WidgetCenter.shared.reloadAllTimelines()
}
}
}
}
@propertyWrapper
public struct UserDefaultsBasicValue<T> {
private let key: String
private let defaultValue: T
private var lastKnownValue: T?
init(wrappedValue defaultValue:T, key:String) {
private let userDefaults: UserDefaults
public init(wrappedValue defaultValue:T, key:String, userDefaults: UserDefaults) {
self.defaultValue = defaultValue
self.key = key
self.userDefaults = userDefaults
}
}
@propertyWrapper
public struct UserDefaultsBasicValue<T> {
public var wrappedValue: T {
get {
let value = UserDefaults.standard.value(forKey: key) as? T
let value = userDefaults.value(forKey: key) as? T
return value ?? defaultValue
}
set {
UserDefaults.standard.setValue(newValue, forKey: key)
UserDefaults.standard.synchronize()
userDefaults.setValue(newValue, forKey: key)
Settings.shared.delegate.invoke { (delegate) in
delegate.settingsDidChange()
}
if #available(iOS 14, *) {
WidgetCenter.shared.reloadAllTimelines()
}
}
}
private let key: String
private let defaultValue: T
init(wrappedValue defaultValue:T, key:String) {
self.defaultValue = defaultValue
self.key = key
}
}
//
// UserDefaults+OneWeather.swift
// OneWeatherCore
//
// Created by Demid Merzlyakov on 18.08.2021.
//
import Foundation
import OneWeatherAnalytics
extension UserDefaults {
private static let appGroup = "group.com.onelouder.oneweather"
public static var appDefaults: UserDefaults {
if let appGroupDefaults = UserDefaults(suiteName: UserDefaults.appGroup) {
return appGroupDefaults
}
// At least it won't crash, but hopefully we'll never end up here.
assertionFailure("Failed to create a shared user defaults.")
return UserDefaults.standard
}
public static func migrateUserDefaultsToAppGroupsIfNeeded() {
// User Defaults - Old
let userDefaults = UserDefaults.standard
// App Groups Default - New
let groupDefaults = UserDefaults.appDefaults
// Key to track if we migrated
let didMigrateToAppGroups = "DidMigrateToAppGroup_\(UserDefaults.appGroup)"
let log = Logger(componentName: "UserDefaults")
if !groupDefaults.bool(forKey: didMigrateToAppGroups) {
for key in userDefaults.dictionaryRepresentation().keys {
groupDefaults.set(userDefaults.dictionaryRepresentation()[key], forKey: key)
}
groupDefaults.set(true, forKey: didMigrateToAppGroups)
groupDefaults.synchronize()
log.info("Successfully migrated defaults")
} else {
log.info("No need to migrate defaults")
}
}
}
......@@ -138,37 +138,37 @@ public enum WindDirection: String, Codable, CaseIterable {
public var degrees: CGFloat {
switch self {
case .north:
return 0
return 180
case .northNorthEast:
return 22.5
return 202.5
case .northEast:
return 45
return 225
case .eastNorthEast:
return 67.5
return 247.5
case .east:
return 90
return 270
case .eastSouthEast:
return 112.5
return 292.5
case .southEast:
return 135
return 315
case .southSouthEast:
return 157.5
return 337.5
case .south:
return 180
return 0
case .southSouthWest:
return 202.5
return 22.5
case .southWest:
return 225
return 45
case .westSouthWest:
return 247.5
return 67.5
case .west:
return 270
return 90
case .westNorthWest:
return 292.5
return 112.5
case .northWest:
return 315
return 135
case .northNorthWest:
return 337.5
return 157.5
}
}
......
......@@ -104,10 +104,11 @@ public class WidgetManager {
public static let shared = WidgetManager()
private init() {
//Load stored options
let storedWidgetsOptions = UserDefaults.standard.integer(forKey: "widgetOptions")
let storedWidgetsOptions = UserDefaults.appDefaults.integer(forKey: "widgetOptions")
self.widgetOptions = WidgetOptions(rawValue: storedWidgetsOptions)
}
private let log = Logger(componentName: "WidgetManager")
private let smartTextProvider = SmartTextProvider()
private var widgetOptions: WidgetOptions = []
public func refreshAnalytics() {
......@@ -127,21 +128,33 @@ public class WidgetManager {
}
let name = WidgetOptions.name(for: option)
var launchParams: [AnalyticsParameter : Any] = [.ANALYTICS_KEY_WIDGET_NAME : name]
if let location = LocationManager.shared.selectedLocation {
let smartText = smartTextProvider.smartText(for: location)
launchParams[.ANALYTICS_KEY_WIDGET_SMART_TEXT] = smartText
}
AppAnalytics.shared.log(event: .ANALYTICS_WIDGET_CARD_CLICK)
AppAnalytics.shared.log(event: .ANALYTICS_LAUNCH_FROM_WIDGET)
AppAnalytics.shared.log(event: .ANALYTICS_WIDGET_LAUNCH_FROM,
params: [.ANALYTICS_KEY_WIDGET_NAME : name])
AppAnalytics.shared.log(event: .ANALYTICS_LAUNCH_FROM_WIDGET, params: launchParams)
}
public func logUpdate() {
public func logUpdate(forLocation location: Location?) {
WidgetCenter.shared.getCurrentConfigurations {[weak self] result in
switch result {
case .success(let widgetInfo):
for info in widgetInfo {
if let option = WidgetOptions.option(forKind: info.kind, family: info.family) {
let name = WidgetOptions.name(for: option)
var params: [AnalyticsParameter : String] = [.ANALYTICS_KEY_WIDGET_NAME : name]
if let updatedLocation = location {
let smartText = self?.smartTextProvider.smartText(for: updatedLocation) ?? ""
params[.ANALYTICS_KEY_WIDGET_SMART_TEXT] = #"\#(smartText)"#
}
AppAnalytics.shared.log(event: .ANALYTICS_WIDGET_UPDATED,
params: [.ANALYTICS_KEY_WIDGET_NAME : name])
params: params)
}
}
case .failure(let error):
......@@ -209,8 +222,8 @@ public class WidgetManager {
}
private func save(options: WidgetOptions) {
UserDefaults.standard.setValue(options.rawValue, forKey: "widgetOptions")
UserDefaults.standard.synchronize()
UserDefaults.appDefaults.setValue(options.rawValue, forKey: "widgetOptions")
UserDefaults.appDefaults.synchronize()
}
}
......
......@@ -34,7 +34,7 @@ public class Settings {
public let delegate = MulticastDelegate<SettingsDelegate>()
private init() {}
@UserDefaultsBasicValue(key: "app_theme")
@UserDefaultsBasicValue(key: "app_theme", userDefaults: UserDefaults.appDefaults)
private var _appTheme = AppTheme.system.rawValue
public var appTheme:AppTheme {
......@@ -61,47 +61,47 @@ public class Settings {
}
}
@UserDefaultsUnitValue(key: "temperature_type")
@UserDefaultsUnitValue(key: "temperature_type", userDefaults: UserDefaults.appDefaults)
public var temperatureType = DefaultSettingsFactory().getSettings().temperatureType
@UserDefaultsUnitValue(key: "wind_speed_type")
@UserDefaultsUnitValue(key: "wind_speed_type", userDefaults: UserDefaults.appDefaults)
public var windSpeedType = DefaultSettingsFactory().getSettings().windSpeedType
@UserDefaultsUnitValue(key: "pressure_type")
@UserDefaultsUnitValue(key: "pressure_type", userDefaults: UserDefaults.appDefaults)
public var pressureType = DefaultSettingsFactory().getSettings().pressureType
@UserDefaultsUnitValue(key: "distance_type")
@UserDefaultsUnitValue(key: "distance_type", userDefaults: UserDefaults.appDefaults)
public var distanceType = DefaultSettingsFactory().getSettings().distanceType
public var locale:Locale {
return Locale(identifier: Localize.currentLanguage())
}
@UserDefaultsBasicValue(key: "pinnedLayers")
@UserDefaultsBasicValue(key: "pinnedLayers", userDefaults: UserDefaults.appDefaults)
public var pinnedLayerIds: [String] = DefaultSettingsFactory().getSettings().pinnedLayerIds
@UserDefaultsBasicValue(key: "selectedLayer")
@UserDefaultsBasicValue(key: "selectedLayer", userDefaults: UserDefaults.appDefaults)
public var selectedLayerId: String = DefaultSettingsFactory().getSettings().selectedLayerId
@UserDefaultsOptionalValue("userQualifiedDate")
@UserDefaultsOptionalValue("userQualifiedDate", userDefaults: UserDefaults.appDefaults)
public var userQualifiedDate: Date?
@UserDefaultsOptionalValue("firstOpenDate")
@UserDefaultsOptionalValue("firstOpenDate", userDefaults: UserDefaults.appDefaults)
public var firstOpenDate: Date?
@UserDefaultsOptionalValue("d3RetentionDate")
@UserDefaultsOptionalValue("d3RetentionDate", userDefaults: UserDefaults.appDefaults)
public var d3RetentionDate: Date?
@UserDefaultsBasicValue(key: "locationDidAdded")
@UserDefaultsBasicValue(key: "locationDidAdded", userDefaults: UserDefaults.appDefaults)
public var locationDidAdded: Bool = false
@UserDefaultsOptionalValue("widgetPromotionTriggerCount")
@UserDefaultsOptionalValue("widgetPromotionTriggerCount", userDefaults: UserDefaults.appDefaults)
public var widgetPromotionTriggerCount: Int?
@UserDefaultsBasicValue(key: "initial_onboarding_showed")
@UserDefaultsBasicValue(key: "initial_onboarding_showed", userDefaults: UserDefaults.appDefaults)
public var initialOnboardingShowed = false
@UserDefaultsBasicValue(key: "shorts_showed_swipeUp_count")
@UserDefaultsBasicValue(key: "shorts_showed_swipeUp_count", userDefaults: UserDefaults.appDefaults)
public var shortsSwipeUpNudgeShowedCount = 0
#warning("Not implemented!")
......
......@@ -20,6 +20,7 @@ class WeatherProvider: TimelineProvider {
typealias Entry = WeatherEntry
var storage: Storage = CoreDataStorage()
var weatherSource: WeatherSource = WdtWeatherSource()
private let logger = Logger(componentName: "WeatherProvider")
func placeholder(in context: Context) -> WeatherEntry {
return WeatherEntry()
......@@ -76,7 +77,7 @@ class WeatherProvider: TimelineProvider {
let nextRefresh = Calendar.current.date(byAdding: .minute, value: 30, to: Date())!
let entry = WeatherEntry(location: fetchedLocation, date: nextRefresh, radarMapImage: mapImage)
let timeline = Timeline(entries: [entry], policy: .atEnd)
WidgetManager.shared.logUpdate()
WidgetManager.shared.logUpdate(forLocation: fetchedLocation)
completion(timeline)
}
}
......@@ -84,9 +85,11 @@ class WeatherProvider: TimelineProvider {
let nextRefresh = Calendar.current.date(byAdding: .minute, value: 30, to: Date())!
let entry = WeatherEntry(location: location, date: nextRefresh)
let timeline = Timeline(entries: [entry], policy: .atEnd)
WidgetManager.shared.logUpdate()
WidgetManager.shared.logUpdate(forLocation: location)
completion(timeline)
}
WidgetManager.shared.refreshAnalytics()
}
}
}
......@@ -12,7 +12,7 @@ struct OneWeatherWidgets: WidgetBundle {
var body: some Widget {
TemperatureWidget()
PrecipitationWidget()
// WindWidget()
// RadarWidget()
WindWidget()
RadarWidget()
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment