mirror of
https://github.com/luxfi/safe-ios.git
synced 2026-10-30 15:19:20 +00:00
225 lines
6.3 KiB
Swift
225 lines
6.3 KiB
Swift
//
|
|
// App.swift
|
|
// Multisig
|
|
//
|
|
// Created by Andrey Scherbovich on 27.05.20.
|
|
// Copyright © 2020 Gnosis Ltd. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import CoreData
|
|
|
|
extension AppSettings {
|
|
static func current() -> AppSettings {
|
|
do {
|
|
let fr = AppSettings.fetchRequest().all()
|
|
let result = try App.shared.coreDataStack.viewContext.fetch(fr)
|
|
return result.first ?? AppSettings(context: App.shared.coreDataStack.viewContext)
|
|
} catch {
|
|
fatalError("Error fetching: \(error)")
|
|
}
|
|
}
|
|
|
|
@AppSetting(\.termsAccepted)
|
|
static var termsAccepted: Bool
|
|
|
|
@AppSetting(\.onboardingCompleted)
|
|
static var onboardingCompleted: Bool
|
|
|
|
@AppSetting(\.trackingEnabled)
|
|
static var trackingEnabled: Bool {
|
|
didSet {
|
|
Tracker.setTrackingEnabled(trackingEnabled)
|
|
}
|
|
}
|
|
|
|
@AppSetting(\.importKeyOnBoardingShown)
|
|
static var hasShownImportKeyOnboarding: Bool
|
|
|
|
@AppSetting(\.dismissedImportKeyBanner)
|
|
static var importKeyBannerDismissed: Bool
|
|
|
|
@AppSetting(\.importedOwnerKey)
|
|
static var importedOwnerKey: Bool
|
|
|
|
@AppSetting(\.appReviewEventCount)
|
|
static var appReviewEventCount: Int64
|
|
|
|
@AppSetting(\.displayMode)
|
|
static var displayMode: Int32
|
|
|
|
@AppSetting(\.fiatCode)
|
|
private static var fiatCode: String?
|
|
|
|
@AppSetting(\.copyAddressWithChainPrefix)
|
|
static var copyAddressWithChainPrefix: Bool
|
|
|
|
@AppSetting(\.prependingChainPrefixToAddresses)
|
|
static var prependingChainPrefixToAddresses: Bool
|
|
|
|
static var selectedFiatCode: String {
|
|
get { fiatCode ?? "USD" }
|
|
set { fiatCode = newValue }
|
|
}
|
|
|
|
@UserDefault(key: "io.gnosis.multisig.importKeyBannerWasShown")
|
|
static var importKeyBannerWasShown: Bool?
|
|
|
|
@UserDefault(key: "io.gnosis.multisig.safeTokenBannerWasShown")
|
|
static var safeTokenBannerWasShown: Bool?
|
|
|
|
@UserDefault(key: "io.gnosis.multisig.relayBannerWasShown")
|
|
static var relayBannerWasShown: Bool?
|
|
|
|
@UserDefault(key: "global.safe.ios.connectToWebDeprecationMessageShown")
|
|
static var didShowDeprecateConnectToWeb: Bool? {
|
|
didSet {
|
|
NotificationCenter.default.post(name: .didReadConnectToWebBanner, object: nil)
|
|
}
|
|
}
|
|
|
|
@AppSetting(\.lastMarketingVersion)
|
|
static var lastMarketingVersion: String?
|
|
|
|
@AppSetting(\.lastBuildVersion)
|
|
static var lastBuildVersion: String?
|
|
|
|
@AppSetting(\.securityCenterVersion)
|
|
static var securityCenterVersion: Int32
|
|
|
|
static var isFreshInstall: Bool {
|
|
// NOTE: historically, we didn't record the currently run
|
|
// app version anywhere, but the termsAccepted exists since
|
|
// the first app release, so this is a way to check for fresh install
|
|
// even for the case when user upgrades their app to the new
|
|
// release version.
|
|
!termsAccepted
|
|
}
|
|
|
|
// MARK: - Security & Passcode
|
|
|
|
// TODO: make a group for security
|
|
|
|
@AppSetting(\.passcodeBannerDismissed)
|
|
static var passcodeBannerDismissed: Bool
|
|
|
|
@AppSetting(\.passcodeWasSetAtLeastOnce)
|
|
static var passcodeWasSetAtLeastOnce: Bool
|
|
|
|
static var shouldOfferToSetupPasscode: Bool {
|
|
get {
|
|
!(passcodeBannerDismissed || passcodeWasSetAtLeastOnce)
|
|
}
|
|
}
|
|
|
|
@AppSetting(\.securityLockEnabled)
|
|
static var securityLockEnabled: Bool
|
|
|
|
static var passcodeOptions: PasscodeOptions {
|
|
get { PasscodeOptions(rawValue: rawPasscodeOptions) }
|
|
set { rawPasscodeOptions = newValue.rawValue }
|
|
}
|
|
|
|
@AppSetting(\.passcodeOptions)
|
|
private static var rawPasscodeOptions: Int64
|
|
|
|
static var securityLockMethod: LockMethod {
|
|
get { LockMethod(rawValue: rawLockMethod)! }
|
|
set { rawLockMethod = newValue.rawValue }
|
|
}
|
|
|
|
|
|
@AppSetting(\.securityLockMethod)
|
|
private static var rawLockMethod: Int16
|
|
|
|
|
|
@AppSetting(\.lastIgnoredUpdateVersion)
|
|
static var lastIgnoredUpdateVersion: String?
|
|
|
|
@AppSetting(\.walletAppRegistryMigrationCompleted)
|
|
static var walletAppRegistryMigrationCompleted: Bool
|
|
}
|
|
|
|
extension AppSettings {
|
|
static func saveCurrentRunVersionNumber() {
|
|
Self.lastMarketingVersion = App.configuration.app.marketingVersion
|
|
Self.lastBuildVersion = App.configuration.app.buildVersion
|
|
}
|
|
}
|
|
|
|
extension NSFetchRequest where ResultType == AppSettings {
|
|
func all() -> Self {
|
|
sortDescriptors = []
|
|
return self
|
|
}
|
|
}
|
|
|
|
@propertyWrapper
|
|
struct AppSetting<T> {
|
|
private var path: ReferenceWritableKeyPath<AppSettings, T>
|
|
|
|
init(_ path: ReferenceWritableKeyPath<AppSettings, T>) {
|
|
self.path = path
|
|
}
|
|
|
|
var wrappedValue: T {
|
|
get {
|
|
let object = AppSettings.current()
|
|
return object[keyPath: path]
|
|
}
|
|
set {
|
|
dispatchPrecondition(condition: .onQueue(.main))
|
|
let object = AppSettings.current()
|
|
object[keyPath: path] = newValue
|
|
App.shared.coreDataStack.saveContext()
|
|
}
|
|
}
|
|
}
|
|
|
|
struct PasscodeOptions: OptionSet {
|
|
let rawValue: Int64
|
|
|
|
// If user wants to enable biometry
|
|
@available(iOS, deprecated: 14, message: "This option is deprecated. Please use `lockMethod` instead.")
|
|
static let useBiometry = PasscodeOptions(rawValue: 1 << 0)
|
|
|
|
// if user wants to authenticate on app opening
|
|
static let useForLogin = PasscodeOptions(rawValue: 1 << 1)
|
|
|
|
// if user wants to authenticate when using the private keys
|
|
static let useForConfirmation = PasscodeOptions(rawValue: 1 << 2)
|
|
|
|
static let all: PasscodeOptions = [.useBiometry, .useForLogin, .useForConfirmation]
|
|
}
|
|
|
|
enum LockMethod: Int16 {
|
|
// authenticate with user-provided passcode
|
|
case passcode = 0
|
|
// authenticate with user's biometry (or device passcode, as a fallback)
|
|
case userPresence = 1
|
|
// authenticate with user-provided passcode and with user's biometry (or device passcode, as a fallback
|
|
case passcodeAndUserPresence = 2
|
|
|
|
func isPasscodeRequired() -> Bool {
|
|
[.passcode, .passcodeAndUserPresence].contains(self)
|
|
}
|
|
|
|
func isUserPresenceRequired() -> Bool {
|
|
[.userPresence, .passcodeAndUserPresence].contains(self)
|
|
}
|
|
}
|
|
|
|
enum BiometryType {
|
|
case faceID
|
|
case touchID
|
|
case passcode
|
|
|
|
var name: String {
|
|
switch self {
|
|
case .faceID: return "Face ID"
|
|
case .touchID: return "Touch ID"
|
|
case .passcode: return "Device Passcode"
|
|
}
|
|
}
|
|
}
|