mirror of
https://github.com/lux-tel/session-ios.git
synced 2026-10-30 20:38:32 +00:00
313 lines
13 KiB
Swift
313 lines
13 KiB
Swift
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
|
//
|
|
// stringlint:disable
|
|
|
|
import Foundation
|
|
|
|
public extension UserDefaultsStorage {
|
|
static var standard: UserDefaultsConfig = Dependencies.create(identifier: "standard") { _ in
|
|
UserDefaults.standard
|
|
}
|
|
static var appGroup: UserDefaultsConfig = Dependencies.create(identifier: UserDefaults.applicationGroup) { _ in
|
|
UserDefaults(suiteName: UserDefaults.applicationGroup)!
|
|
}
|
|
}
|
|
|
|
// MARK: - UserDefaultsType
|
|
|
|
public protocol UserDefaultsType: AnyObject {
|
|
var allKeys: [String] { get }
|
|
|
|
func object(forKey defaultName: String) -> Any?
|
|
func string(forKey defaultName: String) -> String?
|
|
func array(forKey defaultName: String) -> [Any]?
|
|
func dictionary(forKey defaultName: String) -> [String : Any]?
|
|
func data(forKey defaultName: String) -> Data?
|
|
func stringArray(forKey defaultName: String) -> [String]?
|
|
func integer(forKey defaultName: String) -> Int
|
|
func float(forKey defaultName: String) -> Float
|
|
func double(forKey defaultName: String) -> Double
|
|
func bool(forKey defaultName: String) -> Bool
|
|
func url(forKey defaultName: String) -> URL?
|
|
|
|
func set(_ value: Any?, forKey defaultName: String)
|
|
func set(_ value: Int, forKey defaultName: String)
|
|
func set(_ value: Float, forKey defaultName: String)
|
|
func set(_ value: Double, forKey defaultName: String)
|
|
func set(_ value: Bool, forKey defaultName: String)
|
|
func set(_ url: URL?, forKey defaultName: String)
|
|
|
|
func removeObject(forKey defaultName: String)
|
|
func removeAll()
|
|
}
|
|
|
|
public extension UserDefaultsType {
|
|
func removeObject(forKey key: UserDefaults.BoolKey) { self.removeObject(forKey: key.rawValue) }
|
|
func removeObject(forKey key: UserDefaults.DateKey) { self.removeObject(forKey: key.rawValue) }
|
|
func removeObject(forKey key: UserDefaults.DoubleKey) { self.removeObject(forKey: key.rawValue) }
|
|
func removeObject(forKey key: UserDefaults.IntKey) { self.removeObject(forKey: key.rawValue) }
|
|
func removeObject(forKey key: UserDefaults.StringKey) { self.removeObject(forKey: key.rawValue) }
|
|
}
|
|
|
|
extension UserDefaults: UserDefaultsType {}
|
|
|
|
// MARK: - Convenience
|
|
|
|
public extension UserDefaults {
|
|
@ThreadSafeObject private static var cachedApplicationGroup: String = ""
|
|
|
|
// stringlint:ignore_contents
|
|
static let applicationGroup: String = {
|
|
guard !cachedApplicationGroup.isEmpty else {
|
|
let dynamicAppGroupsId: String = (Bundle.main.infoDictionary?["AppGroupsId"] as? String)
|
|
.defaulting(to: "group.com.loki-project.loki-messenger")
|
|
|
|
_cachedApplicationGroup.set(to: dynamicAppGroupsId)
|
|
return dynamicAppGroupsId
|
|
}
|
|
|
|
return cachedApplicationGroup
|
|
}()
|
|
|
|
var allKeys: [String] { Array(self.dictionaryRepresentation().keys) }
|
|
|
|
static func removeAll(using dependencies: Dependencies) {
|
|
UserDefaultsStorage.standard.createInstance(dependencies).removeAll()
|
|
UserDefaultsStorage.appGroup.createInstance(dependencies).removeAll()
|
|
}
|
|
|
|
func removeAll() {
|
|
let data: [String: Any] = self.dictionaryRepresentation()
|
|
data.forEach { key, _ in self.removeObject(forKey: key) }
|
|
self.synchronize() // Shouldn't be needed but better safe than sorry
|
|
}
|
|
}
|
|
|
|
// MARK: - UserDefaults Convenience
|
|
|
|
public extension Dependencies {
|
|
subscript(defaults defaults: UserDefaultsConfig, key key: UserDefaults.BoolKey) -> Bool {
|
|
get { return self[defaults: defaults].bool(forKey: key.rawValue) }
|
|
set {
|
|
self[defaults: defaults].set(newValue, forKey: key.rawValue)
|
|
self.notifyAsync(key: .userDefault(key), value: newValue)
|
|
}
|
|
}
|
|
|
|
subscript(defaults defaults: UserDefaultsConfig, key key: UserDefaults.DateKey) -> Date? {
|
|
get { return self[defaults: defaults].object(forKey: key.rawValue) as? Date }
|
|
set {
|
|
self[defaults: defaults].set(newValue, forKey: key.rawValue)
|
|
self.notifyAsync(key: .userDefault(key), value: newValue)
|
|
}
|
|
}
|
|
|
|
subscript(defaults defaults: UserDefaultsConfig, key key: UserDefaults.DoubleKey) -> Double {
|
|
get { return self[defaults: defaults].double(forKey: key.rawValue) }
|
|
set {
|
|
self[defaults: defaults].set(newValue, forKey: key.rawValue)
|
|
self.notifyAsync(key: .userDefault(key), value: newValue)
|
|
}
|
|
}
|
|
|
|
subscript(defaults defaults: UserDefaultsConfig, key key: UserDefaults.IntKey) -> Int {
|
|
get { return self[defaults: defaults].integer(forKey: key.rawValue) }
|
|
set {
|
|
self[defaults: defaults].set(newValue, forKey: key.rawValue)
|
|
self.notifyAsync(key: .userDefault(key), value: newValue)
|
|
}
|
|
}
|
|
|
|
subscript(defaults defaults: UserDefaultsConfig, key key: UserDefaults.StringKey) -> String? {
|
|
get { return self[defaults: defaults].string(forKey: key.rawValue) }
|
|
set {
|
|
self[defaults: defaults].set(newValue, forKey: key.rawValue)
|
|
self.notifyAsync(key: .userDefault(key), value: newValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - UserDefault Values
|
|
|
|
public extension UserDefaults.BoolKey {
|
|
/// Indicates whether the user has seen the suggestion to enable link previews
|
|
static let hasSeenLinkPreviewSuggestion: UserDefaults.BoolKey = "hasSeenLinkPreviewSuggestion"
|
|
|
|
/// Indicates whether the user has seen the IP exposure warning when enabling calls
|
|
///
|
|
/// **Note:** This is currently not in use (it was decided that it's better to warn the user every time they enable calls instead
|
|
/// of just the first time)
|
|
static let hasSeenCallIPExposureWarning: UserDefaults.BoolKey = "hasSeenCallIPExposureWarning"
|
|
|
|
/// Indicates whether the user has seen the missed call tips modal
|
|
static let hasSeenCallMissedTips: UserDefaults.BoolKey = "hasSeenCallMissedTips"
|
|
|
|
/// Indicates whether the user is registered for APNS (ie. "Fast Mode" notifications)
|
|
static let isUsingFullAPNs: UserDefaults.BoolKey = "isUsingFullAPNs"
|
|
|
|
/// Indicates whether the device was unlinked from an account
|
|
///
|
|
/// **Note:** This doesn't seem to be properly used (we basically just maintain the existing value)
|
|
static let wasUnlinked: UserDefaults.BoolKey = "wasUnlinked"
|
|
|
|
/// Indicates whether the main app is active, this is set to `true` while the app is in the foreground and `false` when
|
|
/// the app is in the background
|
|
static let isMainAppActive: UserDefaults.BoolKey = "isMainAppActive"
|
|
|
|
/// Indicates whether there is an ongoing call
|
|
static let isCallOngoing: UserDefaults.BoolKey = "isCallOngoing"
|
|
|
|
/// Indicates whether we had the microphone permission the last time the app when to the background
|
|
static let lastSeenHasMicrophonePermission: UserDefaults.BoolKey = "lastSeenHasMicrophonePermission"
|
|
|
|
/// Indicates whether we had asked for the local network permission
|
|
static let hasRequestedLocalNetworkPermission: UserDefaults.BoolKey = "hasRequestedLocalNetworkPermission"
|
|
|
|
/// Indicates whether the local notification for token bonus is scheduled
|
|
static let isSessionNetworkPageNotificationScheduled: UserDefaults.BoolKey = "isSessionNetworkPageNotificationScheduled"
|
|
|
|
/// Indicates whether the user visited the Path screen
|
|
static let hasVisitedPathScreen: UserDefaults.BoolKey = "hasVisitedPathScreen"
|
|
|
|
/// Indicates whether the user changed the app theme
|
|
static let hasChangedTheme: UserDefaults.BoolKey = "hasChangedTheme"
|
|
|
|
/// Indicates whether the user pressed the donate button
|
|
static let hasPressedDonateButton: UserDefaults.BoolKey = "hasPressedDonateButton"
|
|
|
|
/// Indicates wheter app has already presented the user the app review prompt dialog
|
|
static let didShowAppReviewPrompt: UserDefaults.BoolKey = "didShowAppReviewPrompt"
|
|
|
|
/// Idicates whether app review prompt was ignored or no iteraction was done to dismiss it (closed app)
|
|
static let didActionAppReviewPrompt: UserDefaults.BoolKey = "didActionAppReviewPrompt"
|
|
|
|
/// Indicates wheter the user should be reminded to grant camera permission for calls
|
|
static let shouldRemindGrantingCameraPermissionForCalls: UserDefaults.BoolKey = "shouldRemindGrantingCameraPermissionForCalls"
|
|
|
|
/// Indicates wheter the app has shown the Pro expiring CTA
|
|
static let hasShownProExpiringCTA: UserDefaults.BoolKey = "hasShownProExpiringCTA"
|
|
|
|
/// Indicates wheter the app has shown the Pro expired CTA
|
|
static let hasShownProExpiredCTA: UserDefaults.BoolKey = "hasShownProExpiredCTA"
|
|
}
|
|
|
|
public extension UserDefaults.DateKey {
|
|
/// The date/time when we re-uploaded or extended the TTL of the users display picture (used for rate-limiting)
|
|
static let lastUserDisplayPictureRefresh: UserDefaults.DateKey = "lastProfilePictureUpload"
|
|
|
|
/// The date/time when any open group last had a successful poll (used as a fallback date/time if the open group hasn't been polled
|
|
/// this session)
|
|
static let lastOpen: UserDefaults.DateKey = "lastOpen"
|
|
|
|
/// The date/time when the last garbage collection was performed (used to rate-limit garbage collection)
|
|
static let lastGarbageCollection: UserDefaults.DateKey = "lastGarbageCollection"
|
|
|
|
/// The date/time when we received a call pre-offer (used to suppress call notifications which are too old)
|
|
static let lastCallPreOffer: UserDefaults.DateKey = "lastCallPreOffer"
|
|
|
|
/// The date/time when app review prompt will appear again
|
|
static let rateAppRetryDate: UserDefaults.DateKey = "rateAppRetryDate"
|
|
}
|
|
|
|
public extension UserDefaults.DoubleKey {
|
|
/// The timestamp when we last successfully uploaded the users push token (used to rate-limit calling our subscription endpoint)
|
|
static let lastDeviceTokenUpload: UserDefaults.DoubleKey = "lastDeviceTokenUploadTime"
|
|
}
|
|
|
|
public extension UserDefaults.IntKey {
|
|
/// The latest hardfork value returned when interacting with a service node
|
|
static let hardfork: UserDefaults.IntKey = "hardfork"
|
|
|
|
/// The latest softfork value returned when interacting with a service node
|
|
static let softfork: UserDefaults.IntKey = "softfork"
|
|
|
|
/// The id of the message that was just shared to
|
|
static let lastSharedMessageId: UserDefaults.IntKey = "lastSharedMessageId"
|
|
|
|
/// The number of attempts made to retry showing of app rating prompt
|
|
static let rateAppRetryAttemptCount: UserDefaults.IntKey = "rateAppRetryAttemptCount"
|
|
}
|
|
|
|
public extension UserDefaults.StringKey {
|
|
/// The most recently subscribed APNS token
|
|
static let deviceToken: UserDefaults.StringKey = "deviceToken"
|
|
|
|
/// The warning to show at the top of the app
|
|
static let topBannerWarningToShow: UserDefaults.StringKey = "topBannerWarningToShow"
|
|
|
|
/// The id of the thread that a message was just shared to
|
|
static let lastSharedThreadId: UserDefaults.StringKey = "lastSharedThreadId"
|
|
|
|
/// The app-icon name of the previously selected app icon disguise
|
|
static let lastSelectedAppIconDisguise: UserDefaults.StringKey = "lastSelectedAppIconDisguise"
|
|
}
|
|
|
|
// MARK: - Keys
|
|
|
|
public extension UserDefaults {
|
|
protocol Key: RawRepresentable, ExpressibleByStringLiteral, Hashable {
|
|
var rawValue: String { get }
|
|
init(_ rawValue: String)
|
|
}
|
|
|
|
struct BoolKey: Key {
|
|
public let rawValue: String
|
|
public init(_ rawValue: String) { self.rawValue = rawValue }
|
|
}
|
|
|
|
struct DateKey: Key {
|
|
public let rawValue: String
|
|
public init(_ rawValue: String) { self.rawValue = rawValue }
|
|
}
|
|
|
|
struct DoubleKey: Key {
|
|
public let rawValue: String
|
|
public init(_ rawValue: String) { self.rawValue = rawValue }
|
|
}
|
|
|
|
struct IntKey: Key {
|
|
public let rawValue: String
|
|
public init(_ rawValue: String) { self.rawValue = rawValue }
|
|
}
|
|
|
|
struct StringKey: Key {
|
|
public let rawValue: String
|
|
public init(_ rawValue: String) { self.rawValue = rawValue }
|
|
}
|
|
}
|
|
|
|
public extension UserDefaults.Key {
|
|
init?(rawValue: String) { self.init(rawValue) }
|
|
init(stringLiteral value: String) { self.init(value) }
|
|
init(unicodeScalarLiteral value: String) { self.init(value) }
|
|
init(extendedGraphemeClusterLiteral value: String) { self.init(value) }
|
|
}
|
|
|
|
// MARK: - Observable Keys
|
|
|
|
public extension ObservableKey {
|
|
static func userDefault(_ key: UserDefaults.BoolKey) -> ObservableKey {
|
|
ObservableKey(key.rawValue, .userDefault)
|
|
}
|
|
|
|
static func userDefault(_ key: UserDefaults.DateKey) -> ObservableKey {
|
|
ObservableKey(key.rawValue, .userDefault)
|
|
}
|
|
|
|
static func userDefault(_ key: UserDefaults.DoubleKey) -> ObservableKey {
|
|
ObservableKey(key.rawValue, .userDefault)
|
|
}
|
|
|
|
static func userDefault(_ key: UserDefaults.IntKey) -> ObservableKey {
|
|
ObservableKey(key.rawValue, .userDefault)
|
|
}
|
|
|
|
static func userDefault(_ key: UserDefaults.StringKey) -> ObservableKey {
|
|
ObservableKey(key.rawValue, .userDefault)
|
|
}
|
|
}
|
|
|
|
public extension GenericObservableKey {
|
|
static let userDefault: GenericObservableKey = "userDefault"
|
|
}
|