diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000000..ac301e4f5c --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +5.8 \ No newline at end of file diff --git a/UnstoppableWallet/IntentExtension/IntentHandler.swift b/UnstoppableWallet/IntentExtension/IntentHandler.swift index 0cfbd9602a..1bbf2847f4 100644 --- a/UnstoppableWallet/IntentExtension/IntentHandler.swift +++ b/UnstoppableWallet/IntentExtension/IntentHandler.swift @@ -24,6 +24,6 @@ class IntentHandler: INExtension, SingleCoinPriceIntentHandling { // This is the default implementation. If you want different objects to handle different intents, // you can override this and return the handler you want for that particular intent. - return self + self } } diff --git a/UnstoppableWallet/UnstoppableWallet/AppDelegate.swift b/UnstoppableWallet/UnstoppableWallet/AppDelegate.swift index 5804a7ac0a..67670cc22e 100644 --- a/UnstoppableWallet/UnstoppableWallet/AppDelegate.swift +++ b/UnstoppableWallet/UnstoppableWallet/AppDelegate.swift @@ -1,13 +1,13 @@ -import UIKit import ThemeKit +import UIKit -@UIApplicationMain +@main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - private var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier.invalid + private var backgroundTask: UIBackgroundTaskIdentifier = .invalid - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Theme.updateNavigationBarTheme() window = ThemeWindow(frame: UIScreen.main.bounds) @@ -24,15 +24,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } - func applicationWillResignActive(_ application: UIApplication) { + func applicationWillResignActive(_: UIApplication) { App.instance?.appManager.willResignActive() } - func applicationDidBecomeActive(_ application: UIApplication) { + func applicationDidBecomeActive(_: UIApplication) { App.instance?.appManager.didBecomeActive() } - func applicationDidEnterBackground(_ application: UIApplication) { + func applicationDidEnterBackground(_: UIApplication) { App.instance?.appManager.didEnterBackground() backgroundTask = UIApplication.shared.beginBackgroundTask { @@ -41,7 +41,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } - func applicationWillEnterForeground(_ application: UIApplication) { + func applicationWillEnterForeground(_: UIApplication) { App.instance?.appManager.willEnterForeground() if backgroundTask != UIBackgroundTaskIdentifier.invalid { @@ -50,31 +50,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } - func applicationWillTerminate(_ application: UIApplication) { + func applicationWillTerminate(_: UIApplication) { App.instance?.appManager.willTerminate() } - func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplication.ExtensionPointIdentifier) -> Bool { + func application(_: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplication.ExtensionPointIdentifier) -> Bool { if extensionPointIdentifier == .keyboard { - //disable custom keyboards + // disable custom keyboards return false } return true } - func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { - } + func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken _: Data) {} - func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool { + func application(_: UIApplication, open url: URL, options _: [UIApplication.OpenURLOptionsKey: Any]) -> Bool { App.instance?.appManager.didReceive(url: url) ?? false } - func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> ()) -> Bool { + func application(_: UIApplication, continue userActivity: NSUserActivity, restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL { return App.instance?.appManager.didReceive(url: url) ?? false } return false } - } diff --git a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/BinanceChainKit.swift b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/BinanceChainKit.swift index 87cf5389ac..8ccea8fd48 100644 --- a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/BinanceChainKit.swift +++ b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/BinanceChainKit.swift @@ -1,26 +1,25 @@ -import Foundation +import BinanceChainKit import Combine -import RxSwift +import Foundation import HsExtensions -import BinanceChainKit - -extension BinanceChainKit { +import RxSwift - struct DisposedError: Error {} +public extension BinanceChainKit { + internal struct DisposedError: Error {} - public var lastBlockHeightObservable: Observable { + var lastBlockHeightObservable: Observable { $lastBlockHeight.asObservable() } - public var syncStateObservable: Observable { + var syncStateObservable: Observable { $syncState.asObservable() } - public func transactionsSingle(symbol: String, filterType: TransactionFilterType? = nil, fromTransactionHash: String? = nil, limit: Int? = nil) -> Single<[TransactionInfo]> { + func transactionsSingle(symbol: String, filterType: TransactionFilterType? = nil, fromTransactionHash: String? = nil, limit: Int? = nil) -> Single<[TransactionInfo]> { Single.just(transactions(symbol: symbol, filterType: filterType, fromTransactionHash: fromTransactionHash, limit: limit)) } - public func sendSingle(symbol: String, to: String, amount: Decimal, memo: String) -> Single { + func sendSingle(symbol: String, to: String, amount: Decimal, memo: String) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -42,7 +41,7 @@ extension BinanceChainKit { } } - public func moveToBSCSingle(symbol: String, amount: Decimal) -> Single { + func moveToBSCSingle(symbol: String, amount: Decimal) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -63,17 +62,14 @@ extension BinanceChainKit { } } } - } -extension Asset { - - public var balanceObservable: Observable { +public extension Asset { + var balanceObservable: Observable { $balance.asObservable() } - public func transactionsObservable(filterType: TransactionFilterType? = nil) -> Observable<[TransactionInfo]> { + func transactionsObservable(filterType: TransactionFilterType? = nil) -> Observable<[TransactionInfo]> { transactionsPublisher(filterType: filterType).asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Eip20Kit.swift b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Eip20Kit.swift index caad299500..5efbd8525d 100644 --- a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Eip20Kit.swift +++ b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Eip20Kit.swift @@ -1,35 +1,35 @@ -import Foundation -import Combine -import RxSwift import BigInt +import Combine +import Eip20Kit import EvmKit +import Foundation import HsToolKit -import Eip20Kit +import RxSwift -extension Eip20Kit.Kit { - struct DisposedError: Error {} +public extension Eip20Kit.Kit { + internal struct DisposedError: Error {} - public func transactionsSingle(from hash: Data?, limit: Int?) throws -> Single<[FullTransaction]> { + func transactionsSingle(from hash: Data?, limit: Int?) throws -> Single<[FullTransaction]> { Single.just(transactions(from: hash, limit: limit)) } - public var syncStateObservable: Observable { + var syncStateObservable: Observable { syncStatePublisher.asObservable() } - public var transactionsSyncStateObservable: Observable { + var transactionsSyncStateObservable: Observable { transactionsSyncStatePublisher.asObservable() } - public var balanceObservable: Observable { + var balanceObservable: Observable { balancePublisher.asObservable() } - public var transactionsObservable: Observable<[FullTransaction]> { + var transactionsObservable: Observable<[FullTransaction]> { transactionsPublisher.asObservable() } - public func allowanceSingle(spenderAddress: EvmKit.Address, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { + func allowanceSingle(spenderAddress: EvmKit.Address, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -51,7 +51,7 @@ extension Eip20Kit.Kit { } } - public static func tokenInfoSingle(networkManager: NetworkManager, rpcSource: RpcSource, contractAddress: EvmKit.Address) -> Single { + static func tokenInfoSingle(networkManager: NetworkManager, rpcSource: RpcSource, contractAddress: EvmKit.Address) -> Single { Single.create { observer in let task = Task { do { @@ -67,5 +67,4 @@ extension Eip20Kit.Kit { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/EvmKit.swift b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/EvmKit.swift index e3cce722c9..25ecae2575 100644 --- a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/EvmKit.swift +++ b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/EvmKit.swift @@ -1,35 +1,34 @@ -import Foundation -import Combine -import RxSwift import BigInt -import HsToolKit +import Combine import EvmKit +import Foundation +import HsToolKit +import RxSwift -extension Kit { - - struct DisposedError: Error {} +public extension Kit { + internal struct DisposedError: Error {} - public var lastBlockHeightObservable: Observable { + var lastBlockHeightObservable: Observable { lastBlockHeightPublisher.asObservable() } - public var syncStateObservable: Observable { + var syncStateObservable: Observable { syncStatePublisher.asObservable() } - public var transactionsSyncStateObservable: Observable { + var transactionsSyncStateObservable: Observable { transactionsSyncStatePublisher.asObservable() } - public var accountStateObservable: Observable { + var accountStateObservable: Observable { accountStatePublisher.asObservable() } - public var allTransactionsObservable: Observable<([FullTransaction], Bool)> { + var allTransactionsObservable: Observable<([FullTransaction], Bool)> { allTransactionsPublisher.asObservable() } - public func transactionSingle(hash: Data) -> Single { + func transactionSingle(hash: Data) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -51,19 +50,19 @@ extension Kit { } } - public func transactionsObservable(tagQueries: [TransactionTagQuery]) -> Observable<[FullTransaction]> { + func transactionsObservable(tagQueries: [TransactionTagQuery]) -> Observable<[FullTransaction]> { transactionsPublisher(tagQueries: tagQueries).asObservable() } - public func transactionsSingle(tagQueries: [TransactionTagQuery], fromHash: Data? = nil, limit: Int? = nil) -> Single<[FullTransaction]> { + func transactionsSingle(tagQueries: [TransactionTagQuery], fromHash: Data? = nil, limit: Int? = nil) -> Single<[FullTransaction]> { Single.just(transactions(tagQueries: tagQueries, fromHash: fromHash, limit: limit)) } - public func rawTransaction(transactionData: TransactionData, gasPrice: GasPrice, gasLimit: Int, nonce: Int? = nil) -> Single { + func rawTransaction(transactionData: TransactionData, gasPrice: GasPrice, gasLimit: Int, nonce: Int? = nil) -> Single { rawTransaction(address: transactionData.to, value: transactionData.value, transactionInput: transactionData.input, gasPrice: gasPrice, gasLimit: gasLimit, nonce: nonce) } - public func rawTransaction(address: EvmKit.Address, value: BigUInt, transactionInput: Data = Data(), gasPrice: GasPrice, gasLimit: Int, nonce: Int? = nil) -> Single { + func rawTransaction(address: EvmKit.Address, value: BigUInt, transactionInput: Data = Data(), gasPrice: GasPrice, gasLimit: Int, nonce: Int? = nil) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -85,7 +84,7 @@ extension Kit { } } - public func nonceSingle(defaultBlockParameter: DefaultBlockParameter) -> Single { + func nonceSingle(defaultBlockParameter: DefaultBlockParameter) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -107,7 +106,7 @@ extension Kit { } } - public func sendSingle(rawTransaction: RawTransaction, signature: Signature) -> Single { + func sendSingle(rawTransaction: RawTransaction, signature: Signature) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -129,7 +128,7 @@ extension Kit { } } - public func getStorageAt(contractAddress: EvmKit.Address, positionData: Data, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { + func getStorageAt(contractAddress: EvmKit.Address, positionData: Data, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -151,7 +150,7 @@ extension Kit { } } - public func call(contractAddress: EvmKit.Address, data: Data, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { + func call(contractAddress: EvmKit.Address, data: Data, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -173,7 +172,7 @@ extension Kit { } } - public func estimateGas(to: EvmKit.Address?, amount: BigUInt, gasPrice: GasPrice) -> Single { + func estimateGas(to: EvmKit.Address?, amount: BigUInt, gasPrice: GasPrice) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -195,7 +194,7 @@ extension Kit { } } - public func estimateGas(to: EvmKit.Address?, amount: BigUInt?, gasPrice: GasPrice, data: Data?) -> Single { + func estimateGas(to: EvmKit.Address?, amount: BigUInt?, gasPrice: GasPrice, data: Data?) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -217,11 +216,11 @@ extension Kit { } } - public func estimateGas(transactionData: TransactionData, gasPrice: GasPrice) -> Single { + func estimateGas(transactionData: TransactionData, gasPrice: GasPrice) -> Single { estimateGas(to: transactionData.to, amount: transactionData.value, gasPrice: gasPrice, data: transactionData.input) } - public static func callSingle(networkManager: NetworkManager, rpcSource: RpcSource, contractAddress: EvmKit.Address, data: Data, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { + static func callSingle(networkManager: NetworkManager, rpcSource: RpcSource, contractAddress: EvmKit.Address, data: Data, defaultBlockParameter: DefaultBlockParameter = .latest) -> Single { Single.create { observer in let task = Task { do { @@ -237,11 +236,9 @@ extension Kit { } } } - } extension L1FeeProvider { - struct DisposedError: Error {} public func getL1Fee(gasPrice: GasPrice, gasLimit: Int, to: EvmKit.Address, value: BigUInt, data: Data) -> Single { @@ -265,11 +262,9 @@ extension L1FeeProvider { } } } - } extension LegacyGasPriceProvider { - struct DisposedError: Error {} public func gasPriceSingle() -> Single { @@ -293,11 +288,9 @@ extension LegacyGasPriceProvider { } } } - } extension Eip1155Provider { - struct DisposedError: Error {} public func getBalanceOf(contractAddress: EvmKit.Address, tokenId: BigUInt, address: EvmKit.Address) -> Single { @@ -321,18 +314,16 @@ extension Eip1155Provider { } } } - } -extension EIP1559GasPriceProvider { +public extension EIP1559GasPriceProvider { + internal struct DisposedError: Error {} - struct DisposedError: Error {} - - public func feeHistoryObservable(blocksCount: Int, defaultBlockParameter: DefaultBlockParameter = .latest, rewardPercentile: [Int]) -> Observable { + func feeHistoryObservable(blocksCount: Int, defaultBlockParameter: DefaultBlockParameter = .latest, rewardPercentile: [Int]) -> Observable { feeHistoryPublisher(blocksCount: blocksCount, defaultBlockParameter: defaultBlockParameter, rewardPercentile: rewardPercentile).asObservable() } - public func feeHistorySingle(blocksCount: Int, defaultBlockParameter: DefaultBlockParameter = .latest, rewardPercentile: [Int]) -> Single { + func feeHistorySingle(blocksCount: Int, defaultBlockParameter: DefaultBlockParameter = .latest, rewardPercentile: [Int]) -> Single { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -353,11 +344,9 @@ extension EIP1559GasPriceProvider { } } } - } extension ENSProvider { - struct DisposedError: Error {} public func address(domain: String) -> Single { @@ -381,5 +370,4 @@ extension ENSProvider { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/HsToolKit.swift b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/HsToolKit.swift index cd4e032a20..0ee43fa8c6 100644 --- a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/HsToolKit.swift +++ b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/HsToolKit.swift @@ -1,13 +1,12 @@ -import Foundation -import Combine -import RxSwift -import ObjectMapper import Alamofire +import Combine +import Foundation import HsToolKit +import ObjectMapper +import RxSwift -extension NetworkManager { - - public func single(request: DataRequest, mapper: Mapper, sync: Bool = false, postDelay: TimeInterval? = nil) -> Single { +public extension NetworkManager { + func single(request: DataRequest, mapper: Mapper, sync _: Bool = false, postDelay _: TimeInterval? = nil) -> Single { Single.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -30,8 +29,9 @@ extension NetworkManager { } } - public func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters, mapper: Mapper, encoding: ParameterEncoding = URLEncoding.default, - headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil) -> Single { + func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters, mapper: Mapper, encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil) -> Single + { Single.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -54,7 +54,7 @@ extension NetworkManager { } } - public func single(request: DataRequest, sync: Bool = false, postDelay: TimeInterval? = nil) -> Single { + func single(request: DataRequest, sync _: Bool = false, postDelay _: TimeInterval? = nil) -> Single { Single.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -76,7 +76,7 @@ extension NetworkManager { } } - public func single(request: DataRequest, sync: Bool = false, postDelay: TimeInterval = 0, context: MapContext? = nil) -> Single { + func single(request: DataRequest, sync _: Bool = false, postDelay _: TimeInterval = 0, context: MapContext? = nil) -> Single { Single.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -99,7 +99,7 @@ extension NetworkManager { } } - public func single(request: DataRequest, context: MapContext? = nil) -> Single<[T]> { + func single(request: DataRequest, context: MapContext? = nil) -> Single<[T]> { Single<[T]>.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -122,7 +122,7 @@ extension NetworkManager { } } - public func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters = [:], encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil, context: MapContext? = nil) -> Single { + func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters = [:], encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil, context: MapContext? = nil) -> Single { Single.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -144,7 +144,7 @@ extension NetworkManager { } } - public func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters = [:], encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil, context: MapContext? = nil) -> Single<[T]> { + func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters = [:], encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil, context: MapContext? = nil) -> Single<[T]> { Single<[T]>.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -166,7 +166,7 @@ extension NetworkManager { } } - public func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters = [:], encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil, context: MapContext? = nil) -> Single<[String: T]> { + func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters = [:], encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil, context: MapContext? = nil) -> Single<[String: T]> { Single<[String: T]>.create { [weak self] observer in guard let manager = self else { observer(.error(NetworkManager.RequestError.disposed)) @@ -188,12 +188,11 @@ extension NetworkManager { } } - public enum RequestError: Error { + enum RequestError: Error { case invalidResponse(statusCode: Int, data: Any?) case noResponse(reason: String?) case disposed } - } public protocol IReachabilityManager { @@ -203,7 +202,6 @@ public protocol IReachabilityManager { } extension ReachabilityManager: IReachabilityManager { - public var reachabilityObservable: Observable { $isReachable.asObservable() } @@ -211,15 +209,12 @@ extension ReachabilityManager: IReachabilityManager { public var connectionTypeUpdatedObservable: Observable { connectionTypeChangedPublisher.asObservable() } - } -extension BackgroundModeObserver { - - public var foregroundFromExpiredBackgroundObservable: Observable { +public extension BackgroundModeObserver { + var foregroundFromExpiredBackgroundObservable: Observable { foregroundFromExpiredBackgroundPublisher.asObservable() } - } public protocol IApiMapper { @@ -235,7 +230,8 @@ public class SerialNetworkManager { } public func single(url: URLConvertible, method: HTTPMethod, parameters: Parameters, mapper: Mapper, encoding: ParameterEncoding = URLEncoding.default, - headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil) -> Single { + headers: HTTPHeaders? = nil, interceptor: RequestInterceptor? = nil, responseCacherBehavior: ResponseCacher.Behavior? = nil) -> Single + { Single.create { [weak self] observer in guard let manager = self?.networkManager else { observer(.error(NetworkManager.RequestError.disposed)) @@ -257,5 +253,4 @@ public class SerialNetworkManager { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/NftKit.swift b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/NftKit.swift index 3913a7387e..0369f3ba2a 100644 --- a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/NftKit.swift +++ b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/NftKit.swift @@ -1,8 +1,8 @@ -import Foundation import Combine -import RxSwift +import Foundation import HsToolKit import NftKit +import RxSwift extension Kit { struct DisposedError: Error {} @@ -10,5 +10,4 @@ extension Kit { public var nftBalancesObservable: Observable<[NftBalance]> { nftBalancesPublisher.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/OneInchKit.swift b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/OneInchKit.swift index 2e8d7a6e24..71686b686a 100644 --- a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/OneInchKit.swift +++ b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/OneInchKit.swift @@ -1,24 +1,25 @@ -import Foundation -import Combine -import RxSwift import BigInt +import Combine import EvmKit +import Foundation import HsToolKit import OneInchKit +import RxSwift -extension OneInchKit.Kit { - struct DisposedError: Error {} +public extension OneInchKit.Kit { + internal struct DisposedError: Error {} - public func quoteSingle(fromToken: EvmKit.Address, - toToken: EvmKit.Address, - amount: BigUInt, - protocols: String? = nil, - gasPrice: GasPrice? = nil, - complexityLevel: Int? = nil, - connectorTokens: String? = nil, - gasLimit: Int? = nil, - mainRouteParts: Int? = nil, - parts: Int? = nil) -> Single { + func quoteSingle(fromToken: EvmKit.Address, + toToken: EvmKit.Address, + amount: BigUInt, + protocols: String? = nil, + gasPrice: GasPrice? = nil, + complexityLevel: Int? = nil, + connectorTokens: String? = nil, + gasLimit: Int? = nil, + mainRouteParts: Int? = nil, + parts: Int? = nil) -> Single + { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -28,16 +29,16 @@ extension OneInchKit.Kit { let task = Task { do { let result = try await strongSelf.quote( - fromToken: fromToken, - toToken: toToken, - amount: amount, - protocols: protocols, - gasPrice: gasPrice, - complexityLevel: complexityLevel, - connectorTokens: connectorTokens, - gasLimit: gasLimit, - mainRouteParts: mainRouteParts, - parts: parts + fromToken: fromToken, + toToken: toToken, + amount: amount, + protocols: protocols, + gasPrice: gasPrice, + complexityLevel: complexityLevel, + connectorTokens: connectorTokens, + gasLimit: gasLimit, + mainRouteParts: mainRouteParts, + parts: parts ) observer(.success(result)) } catch { @@ -51,20 +52,21 @@ extension OneInchKit.Kit { } } - public func swapSingle(fromToken: EvmKit.Address, - toToken: EvmKit.Address, - amount: BigUInt, - slippage: Decimal, - protocols: [String]? = nil, - recipient: EvmKit.Address? = nil, - gasPrice: GasPrice? = nil, - burnChi: Bool? = nil, - complexityLevel: Int? = nil, - connectorTokens: [String]? = nil, - allowPartialFill: Bool? = nil, - gasLimit: Int? = nil, - mainRouteParts: Int? = nil, - parts: Int? = nil) -> Single { + func swapSingle(fromToken: EvmKit.Address, + toToken: EvmKit.Address, + amount: BigUInt, + slippage: Decimal, + protocols: [String]? = nil, + recipient: EvmKit.Address? = nil, + gasPrice: GasPrice? = nil, + burnChi: Bool? = nil, + complexityLevel: Int? = nil, + connectorTokens: [String]? = nil, + allowPartialFill: Bool? = nil, + gasLimit: Int? = nil, + mainRouteParts: Int? = nil, + parts: Int? = nil) -> Single + { Single.create { [weak self] observer in guard let strongSelf = self else { observer(.error(DisposedError())) @@ -74,20 +76,20 @@ extension OneInchKit.Kit { let task = Task { do { let result = try await strongSelf.swap( - fromToken: fromToken, - toToken: toToken, - amount: amount, - slippage: slippage, - protocols: protocols, - recipient: recipient, - gasPrice: gasPrice, - burnChi: burnChi, - complexityLevel: complexityLevel, - connectorTokens: connectorTokens, - allowPartialFill: allowPartialFill, - gasLimit: gasLimit, - mainRouteParts: mainRouteParts, - parts: parts + fromToken: fromToken, + toToken: toToken, + amount: amount, + slippage: slippage, + protocols: protocols, + recipient: recipient, + gasPrice: gasPrice, + burnChi: burnChi, + complexityLevel: complexityLevel, + connectorTokens: connectorTokens, + allowPartialFill: allowPartialFill, + gasLimit: gasLimit, + mainRouteParts: mainRouteParts, + parts: parts ) observer(.success(result)) } catch { @@ -100,5 +102,4 @@ extension OneInchKit.Kit { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Publisher.swift b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Publisher.swift index 9133802f52..3f2e10b89b 100644 --- a/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Publisher.swift +++ b/UnstoppableWallet/UnstoppableWallet/BackCompatibility/Publisher.swift @@ -11,17 +11,18 @@ extension Publisher { func asObservable() -> Observable { Observable.create { observer in let cancellable = self.sink( - receiveCompletion: { completion in - switch completion { - case .finished: - observer.onCompleted() - case .failure(let error): - observer.onError(error) - } - }, - receiveValue: { value in - observer.onNext(value) - }) + receiveCompletion: { completion in + switch completion { + case .finished: + observer.onCompleted() + case let .failure(error): + observer.onError(error) + } + }, + receiveValue: { value in + observer.onNext(value) + } + ) return Disposables.create { cancellable.cancel() diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BinanceAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BinanceAdapter.swift index ddfa4bce3b..f6d2221d52 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BinanceAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BinanceAdapter.swift @@ -1,7 +1,7 @@ -import Foundation -import RxSwift import BinanceChainKit +import Foundation import MarketKit +import RxSwift class BinanceAdapter { static let confirmationsThreshold = 1 @@ -22,7 +22,7 @@ class BinanceAdapter { let symbol: String switch token.type { - case .bep2(let value): symbol = value + case let .bep2(value): symbol = value default: symbol = "BNB" } @@ -33,9 +33,9 @@ class BinanceAdapter { let fromMine = transaction.from == binanceKit.account let toMine = transaction.to == binanceKit.account - if fromMine && !toMine { + if fromMine, !toMine { return BinanceChainOutgoingTransactionRecord(source: transactionSource, transaction: transaction, feeToken: feeToken, token: token, sentToSelf: false) - } else if !fromMine && toMine { + } else if !fromMine, toMine { return BinanceChainIncomingTransactionRecord(source: transactionSource, transaction: transaction, feeToken: feeToken, token: token) } else { return BinanceChainOutgoingTransactionRecord(source: transactionSource, transaction: transaction, feeToken: feeToken, token: token, sentToSelf: true) @@ -45,7 +45,7 @@ class BinanceAdapter { private func adapterState(syncState: BinanceChainKit.SyncState) -> AdapterState { switch syncState { case .synced: return .synced - case .notSynced(let error): return .notSynced(error: error.convertedError) + case let .notSynced(error): return .notSynced(error: error.convertedError) case .syncing: return .syncing(progress: nil, lastBlockDate: nil) } } @@ -53,11 +53,10 @@ class BinanceAdapter { private func balanceInfo(balance: Decimal) -> BalanceData { BalanceData(available: balance) } - } extension BinanceAdapter { - //todo: Make binanceKit errors public! + // TODO: Make binanceKit errors public! enum AddressConversion: Error { case invalidAddress } @@ -65,11 +64,9 @@ extension BinanceAdapter { static func clear(except excludedWalletIds: [String]) throws { try BinanceChainKit.clear(exceptFor: excludedWalletIds) } - } extension BinanceAdapter: IAdapter { - var isMainNet: Bool { true } @@ -93,11 +90,9 @@ extension BinanceAdapter: IAdapter { var debugInfo: String { "" } - } extension BinanceAdapter: IBalanceAdapter { - var balanceState: AdapterState { adapterState(syncState: binanceKit.syncState) } @@ -117,11 +112,9 @@ extension BinanceAdapter: IBalanceAdapter { self?.balanceInfo(balance: $0) ?? BalanceData(available: 0) } } - } extension BinanceAdapter: ISendBinanceAdapter { - var availableBalance: Decimal { var balance = asset.balance if asset.symbol == "BNB" { @@ -135,7 +128,7 @@ extension BinanceAdapter: ISendBinanceAdapter { } func validate(address: String) throws { - //todo: remove when make errors public + // TODO: remove when make errors public do { try binanceKit.validate(address: address) } catch { @@ -149,13 +142,11 @@ extension BinanceAdapter: ISendBinanceAdapter { func sendSingle(amount: Decimal, address: String, memo: String?) -> Single { binanceKit.sendSingle(symbol: asset.symbol, to: address, amount: amount, memo: memo ?? "") - .map { _ in () } + .map { _ in () } } - } extension BinanceAdapter: ITransactionsAdapter { - var syncing: Bool { if case .syncing = binanceKit.syncState { return true } return false @@ -179,17 +170,17 @@ extension BinanceAdapter: ITransactionsAdapter { func explorerUrl(transactionHash: String) -> String? { binanceKit.networkType == .mainNet - ? "https://explorer.binance.org/tx/" + transactionHash - : "https://testnet-explorer.binance.org/tx/" + transactionHash + ? "https://explorer.binance.org/tx/" + transactionHash + : "https://testnet-explorer.binance.org/tx/" + transactionHash } - func transactionsObservable(token: Token?, filter: TransactionTypeFilter) -> Observable<[TransactionRecord]> { + func transactionsObservable(token _: Token?, filter: TransactionTypeFilter) -> Observable<[TransactionRecord]> { let binanceChainFilter: TransactionFilterType? switch filter { - case .all: binanceChainFilter = nil - case .incoming: binanceChainFilter = .incoming - case .outgoing: binanceChainFilter = .outgoing - default: return Observable.just([]) + case .all: binanceChainFilter = nil + case .incoming: binanceChainFilter = .incoming + case .outgoing: binanceChainFilter = .outgoing + default: return Observable.just([]) } return asset.transactionsObservable(filterType: binanceChainFilter).map { [weak self] in @@ -199,32 +190,29 @@ extension BinanceAdapter: ITransactionsAdapter { } } - func transactionsSingle(from: TransactionRecord?, token: Token?, filter: TransactionTypeFilter, limit: Int) -> Single<[TransactionRecord]> { + func transactionsSingle(from: TransactionRecord?, token _: Token?, filter: TransactionTypeFilter, limit: Int) -> Single<[TransactionRecord]> { let binanceChainFilter: TransactionFilterType? switch filter { - case .all: binanceChainFilter = nil - case .incoming: binanceChainFilter = .incoming - case .outgoing: binanceChainFilter = .outgoing - default: return Single.just([]) + case .all: binanceChainFilter = nil + case .incoming: binanceChainFilter = .incoming + case .outgoing: binanceChainFilter = .outgoing + default: return Single.just([]) } return binanceKit.transactionsSingle(symbol: asset.symbol, filterType: binanceChainFilter, fromTransactionHash: from?.transactionHash, limit: limit) - .map { [weak self] transactions -> [TransactionRecord] in - transactions.compactMap { self?.transactionRecord(fromTransaction: $0) } - } + .map { [weak self] transactions -> [TransactionRecord] in + transactions.compactMap { self?.transactionRecord(fromTransaction: $0) } + } } - func rawTransaction(hash: String) -> String? { + func rawTransaction(hash _: String) -> String? { nil } - } extension BinanceAdapter: IDepositAdapter { - var receiveAddress: DepositAddress { DepositAddress(binanceKit.account) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinAdapter.swift index 7cc6db16c1..8ca6bc3d92 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinAdapter.swift @@ -1,8 +1,8 @@ -import BitcoinKit import BitcoinCore -import RxSwift +import BitcoinKit import HdWalletKit import MarketKit +import RxSwift class BitcoinAdapter: BitcoinBaseAdapter { private let bitcoinKit: BitcoinKit.Kit @@ -22,13 +22,13 @@ class BitcoinAdapter: BitcoinBaseAdapter { } bitcoinKit = try BitcoinKit.Kit( - seed: seed, - purpose: derivation.purpose, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, - logger: logger + seed: seed, + purpose: derivation.purpose, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, + logger: logger ) case let .hdExtendedKey(key): guard let derivation = wallet.token.type.derivation else { @@ -36,13 +36,13 @@ class BitcoinAdapter: BitcoinBaseAdapter { } bitcoinKit = try BitcoinKit.Kit( - extendedKey: key, - purpose: derivation.purpose, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, - logger: logger + extendedKey: key, + purpose: derivation.purpose, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, + logger: logger ) default: throw AdapterError.unsupportedAccount @@ -60,21 +60,16 @@ class BitcoinAdapter: BitcoinBaseAdapter { override func explorerUrl(transactionHash: String) -> String? { "https://blockchair.com/bitcoin/transaction/" + transactionHash } - } extension BitcoinAdapter: ISendBitcoinAdapter { - var blockchainType: BlockchainType { .bitcoin } - } extension BitcoinAdapter { - static func clear(except excludedWalletIds: [String]) throws { try Kit.clear(exceptFor: excludedWalletIds) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinBaseAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinBaseAdapter.swift index 2bd2f90cbf..e72ad91d2a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinBaseAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinBaseAdapter.swift @@ -1,16 +1,16 @@ -import Foundation import BitcoinCore +import Foundation +import HdWalletKit import Hodler -import RxSwift import HsToolKit import MarketKit -import HdWalletKit +import RxSwift class BitcoinBaseAdapter { static let confirmationsThreshold = 3 private let abstractKit: AbstractKit - var coinRate: Decimal { 100_000_000 } //pow(10, 8) + var coinRate: Decimal { 100_000_000 } // pow(10, 8) private let lastBlockUpdatedSubject = PublishSubject() private let balanceStateSubject = PublishSubject() @@ -23,6 +23,7 @@ class BitcoinBaseAdapter { syncing = balanceState.syncing } } + private(set) var syncing: Bool = true private let token: Token @@ -54,11 +55,11 @@ class BitcoinBaseAdapter { if let pluginId = output.pluginId, pluginId == HodlerPlugin.id, let hodlerOutputData = output.pluginData as? HodlerOutputData, - let approximateUnlockTime = hodlerOutputData.approximateUnlockTime { - + let approximateUnlockTime = hodlerOutputData.approximateUnlockTime + { lockInfo = TransactionLockInfo( - lockedUntil: Date(timeIntervalSince1970: Double(approximateUnlockTime)), - originalAddress: hodlerOutputData.addressString + lockedUntil: Date(timeIntervalSince1970: Double(approximateUnlockTime)), + originalAddress: hodlerOutputData.addressString ) } if anyNotMineToAddress == nil, let address = output.address, !output.mine { @@ -69,59 +70,59 @@ class BitcoinBaseAdapter { switch transaction.type { case .incoming: return BitcoinIncomingTransactionRecord( - token: token, - source: transactionSource, - uid: transaction.uid, - transactionHash: transaction.transactionHash, - transactionIndex: transaction.transactionIndex, - blockHeight: transaction.blockHeight, - confirmationsThreshold: Self.confirmationsThreshold, - date: Date(timeIntervalSince1970: Double(transaction.timestamp)), - fee: transaction.fee.map { Decimal($0) / coinRate }, - failed: transaction.status == .invalid, - lockInfo: lockInfo, - conflictingHash: transaction.conflictingHash, - showRawTransaction: transaction.status == .new || transaction.status == .invalid, - amount: Decimal(transaction.amount) / coinRate, - from: anyNotMineFromAddress + token: token, + source: transactionSource, + uid: transaction.uid, + transactionHash: transaction.transactionHash, + transactionIndex: transaction.transactionIndex, + blockHeight: transaction.blockHeight, + confirmationsThreshold: Self.confirmationsThreshold, + date: Date(timeIntervalSince1970: Double(transaction.timestamp)), + fee: transaction.fee.map { Decimal($0) / coinRate }, + failed: transaction.status == .invalid, + lockInfo: lockInfo, + conflictingHash: transaction.conflictingHash, + showRawTransaction: transaction.status == .new || transaction.status == .invalid, + amount: Decimal(transaction.amount) / coinRate, + from: anyNotMineFromAddress ) case .outgoing: return BitcoinOutgoingTransactionRecord( - token: token, - source: transactionSource, - uid: transaction.uid, - transactionHash: transaction.transactionHash, - transactionIndex: transaction.transactionIndex, - blockHeight: transaction.blockHeight, - confirmationsThreshold: Self.confirmationsThreshold, - date: Date(timeIntervalSince1970: Double(transaction.timestamp)), - fee: transaction.fee.map { Decimal($0) / coinRate }, - failed: transaction.status == .invalid, - lockInfo: lockInfo, - conflictingHash: transaction.conflictingHash, - showRawTransaction: transaction.status == .new || transaction.status == .invalid, - amount: Decimal(transaction.amount) / coinRate, - to: anyNotMineToAddress, - sentToSelf: false + token: token, + source: transactionSource, + uid: transaction.uid, + transactionHash: transaction.transactionHash, + transactionIndex: transaction.transactionIndex, + blockHeight: transaction.blockHeight, + confirmationsThreshold: Self.confirmationsThreshold, + date: Date(timeIntervalSince1970: Double(transaction.timestamp)), + fee: transaction.fee.map { Decimal($0) / coinRate }, + failed: transaction.status == .invalid, + lockInfo: lockInfo, + conflictingHash: transaction.conflictingHash, + showRawTransaction: transaction.status == .new || transaction.status == .invalid, + amount: Decimal(transaction.amount) / coinRate, + to: anyNotMineToAddress, + sentToSelf: false ) case .sentToSelf: return BitcoinOutgoingTransactionRecord( - token: token, - source: transactionSource, - uid: transaction.uid, - transactionHash: transaction.transactionHash, - transactionIndex: transaction.transactionIndex, - blockHeight: transaction.blockHeight, - confirmationsThreshold: Self.confirmationsThreshold, - date: Date(timeIntervalSince1970: Double(transaction.timestamp)), - fee: transaction.fee.map { Decimal($0) / coinRate }, - failed: transaction.status == .invalid, - lockInfo: lockInfo, - conflictingHash: transaction.conflictingHash, - showRawTransaction: transaction.status == .new || transaction.status == .invalid, - amount: Decimal(transaction.amount) / coinRate, - to: anyNotMineToAddress, - sentToSelf: true + token: token, + source: transactionSource, + uid: transaction.uid, + transactionHash: transaction.transactionHash, + transactionIndex: transaction.transactionIndex, + blockHeight: transaction.blockHeight, + confirmationsThreshold: Self.confirmationsThreshold, + date: Date(timeIntervalSince1970: Double(transaction.timestamp)), + fee: transaction.fee.map { Decimal($0) / coinRate }, + failed: transaction.status == .invalid, + lockInfo: lockInfo, + conflictingHash: transaction.conflictingHash, + showRawTransaction: transaction.status == .new || transaction.status == .invalid, + amount: Decimal(transaction.amount) / coinRate, + to: anyNotMineToAddress, + sentToSelf: true ) } } @@ -141,8 +142,8 @@ class BitcoinBaseAdapter { private func balanceData(balanceInfo: BalanceInfo) -> BalanceData { LockedBalanceData( - available: Decimal(balanceInfo.spendable) / coinRate, - locked: Decimal(balanceInfo.unspendable) / coinRate + available: Decimal(balanceInfo.spendable) / coinRate, + locked: Decimal(balanceInfo.unspendable) / coinRate ) } @@ -150,14 +151,12 @@ class BitcoinBaseAdapter { fatalError("Must be overridden by subclass") } - open func explorerUrl(transactionHash: String) -> String? { + open func explorerUrl(transactionHash _: String) -> String? { fatalError("Must be overridden by subclass") } - } extension BitcoinBaseAdapter: IAdapter { - var isMainNet: Bool { true } @@ -182,11 +181,9 @@ extension BitcoinBaseAdapter: IAdapter { var statusInfo: [(String, Any)] { abstractKit.statusInfo } - } extension BitcoinBaseAdapter: BitcoinCoreDelegate { - func transactionsUpdated(inserted: [TransactionInfo], updated: [TransactionInfo]) { var records = [BitcoinTransactionRecord]() @@ -200,14 +197,13 @@ extension BitcoinBaseAdapter: BitcoinCoreDelegate { transactionRecordsSubject.onNext(records) } - func transactionsDeleted(hashes: [String]) { - } + func transactionsDeleted(hashes _: [String]) {} func balanceUpdated(balance: BalanceInfo) { balanceSubject.onNext(balanceData(balanceInfo: balance)) } - func lastBlockInfoUpdated(lastBlockInfo: BlockInfo) { + func lastBlockInfoUpdated(lastBlockInfo _: BlockInfo) { lastBlockUpdatedSubject.onNext(()) } @@ -219,39 +215,37 @@ extension BitcoinBaseAdapter: BitcoinCoreDelegate { } balanceState = .synced - case .notSynced(let error): + case let .notSynced(error): let converted = error.convertedError - if case .notSynced(let appError) = balanceState, "\(converted)" == "\(appError)" { + if case let .notSynced(appError) = balanceState, "\(converted)" == "\(appError)" { return } balanceState = .notSynced(error: converted) - case .syncing(let progress): + case let .syncing(progress): let newProgress = Int(progress * 100) let newDate = abstractKit.lastBlockInfo?.timestamp.map { Date(timeIntervalSince1970: Double($0)) } if case let .syncing(currentProgress, currentDate) = balanceState, newProgress == currentProgress { - if let currentDate = currentDate, let newDate = newDate, currentDate.isSameDay(as: newDate) { + if let currentDate, let newDate, currentDate.isSameDay(as: newDate) { return } } balanceState = .syncing(progress: newProgress, lastBlockDate: newDate) - case .apiSyncing(let newCount): + case let .apiSyncing(newCount): let newCountDescription = "balance.searching.count".localized("\(newCount)") - if case .customSyncing(_, let secondary, _) = balanceState, newCountDescription == secondary { + if case let .customSyncing(_, secondary, _) = balanceState, newCountDescription == secondary { return } balanceState = .customSyncing(main: "balance.searching".localized(), secondary: newCountDescription, progress: nil) } } - } extension BitcoinBaseAdapter: IBalanceAdapter { - var balanceStateUpdatedObservable: Observable { balanceStateSubject.asObservable() } @@ -263,11 +257,9 @@ extension BitcoinBaseAdapter: IBalanceAdapter { var balanceDataUpdatedObservable: Observable { balanceSubject.asObservable() } - } extension BitcoinBaseAdapter { - func availableBalance(feeRate: Int, address: String?, pluginData: [UInt8: IBitcoinPluginData] = [:]) -> Decimal { let amount = (try? abstractKit.maxSpendableValue(toAddress: address, feeRate: feeRate, pluginData: pluginData)) ?? 0 return Decimal(amount) / coinRate @@ -279,7 +271,7 @@ extension BitcoinBaseAdapter { func minimumSendAmount(address: String?) -> Decimal { do { - return Decimal(try abstractKit.minSpendableValue(toAddress: address)) / coinRate + return try Decimal(abstractKit.minSpendableValue(toAddress: address)) / coinRate } catch { return 0 } @@ -321,11 +313,9 @@ extension BitcoinBaseAdapter { return Disposables.create() } } - } extension BitcoinBaseAdapter: ITransactionsAdapter { - var lastBlockInfo: LastBlockInfo? { abstractKit.lastBlockInfo.map { LastBlockInfo(height: $0.height, timestamp: $0.timestamp) } } @@ -338,23 +328,23 @@ extension BitcoinBaseAdapter: ITransactionsAdapter { lastBlockUpdatedSubject.asObservable() } - func transactionsObservable(token: Token?, filter: TransactionTypeFilter) -> Observable<[TransactionRecord]> { + func transactionsObservable(token _: Token?, filter: TransactionTypeFilter) -> Observable<[TransactionRecord]> { transactionRecordsSubject.asObservable() - .map { transactions in - transactions.compactMap { transaction -> TransactionRecord? in - switch (transaction, filter) { - case (_, .all): return transaction - case (is BitcoinIncomingTransactionRecord, .incoming): return transaction - case (is BitcoinOutgoingTransactionRecord, .outgoing): return transaction - case (let tx as BitcoinOutgoingTransactionRecord, .incoming): return tx.sentToSelf ? transaction : nil - default: return nil - } + .map { transactions in + transactions.compactMap { transaction -> TransactionRecord? in + switch (transaction, filter) { + case (_, .all): return transaction + case (is BitcoinIncomingTransactionRecord, .incoming): return transaction + case (is BitcoinOutgoingTransactionRecord, .outgoing): return transaction + case let (tx as BitcoinOutgoingTransactionRecord, .incoming): return tx.sentToSelf ? transaction : nil + default: return nil } } - .filter { !$0.isEmpty } + } + .filter { !$0.isEmpty } } - func transactionsSingle(from: TransactionRecord?, token: Token?, filter: TransactionTypeFilter, limit: Int) -> Single<[TransactionRecord]> { + func transactionsSingle(from: TransactionRecord?, token _: Token?, filter: TransactionTypeFilter, limit: Int) -> Single<[TransactionRecord]> { let bitcoinFilter: TransactionFilterType? switch filter { case .all: bitcoinFilter = nil @@ -364,9 +354,9 @@ extension BitcoinBaseAdapter: ITransactionsAdapter { } let transactions = abstractKit.transactions(fromUid: from?.uid, type: bitcoinFilter, limit: limit) - .map { - transactionRecord(fromTransaction: $0) - } + .map { + transactionRecord(fromTransaction: $0) + } return Single.just(transactions) } @@ -374,15 +364,12 @@ extension BitcoinBaseAdapter: ITransactionsAdapter { func rawTransaction(hash: String) -> String? { abstractKit.rawTransaction(transactionHash: hash) } - } extension BitcoinBaseAdapter: IDepositAdapter { - var receiveAddress: DepositAddress { DepositAddress(abstractKit.receiveAddress()) } - } class DepositAddress { diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinCashAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinCashAdapter.swift index 7bfb340e1e..f24451ddba 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinCashAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/BitcoinCashAdapter.swift @@ -1,8 +1,8 @@ import BitcoinCashKit import BitcoinCore -import RxSwift -import MarketKit import HdWalletKit +import MarketKit +import RxSwift class BitcoinCashAdapter: BitcoinBaseAdapter { private let bitcoinCashKit: BitcoinCashKit.Kit @@ -29,21 +29,21 @@ class BitcoinCashAdapter: BitcoinBaseAdapter { } bitcoinCashKit = try BitcoinCashKit.Kit( - seed: seed, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, - logger: logger + seed: seed, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, + logger: logger ) case let .hdExtendedKey(key): bitcoinCashKit = try BitcoinCashKit.Kit( - extendedKey: key, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, - logger: logger + extendedKey: key, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, + logger: logger ) default: throw AdapterError.unsupportedAccount @@ -61,21 +61,16 @@ class BitcoinCashAdapter: BitcoinBaseAdapter { override func explorerUrl(transactionHash: String) -> String? { "https://bch.btc.com/" + transactionHash } - } extension BitcoinCashAdapter: ISendBitcoinAdapter { - var blockchainType: BlockchainType { .bitcoinCash } - } extension BitcoinCashAdapter { - static func clear(except excludedWalletIds: [String]) throws { try Kit.clear(exceptFor: excludedWalletIds) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/DashAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/DashAdapter.swift index 433460bcdf..d70d7b5a25 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/DashAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/DashAdapter.swift @@ -1,10 +1,10 @@ -import Foundation +import BitcoinCore import DashKit -import RxSwift +import Foundation +import HdWalletKit import HsToolKit -import BitcoinCore import MarketKit -import HdWalletKit +import RxSwift class DashAdapter: BitcoinBaseAdapter { private let feeRate = 1 @@ -22,21 +22,21 @@ class DashAdapter: BitcoinBaseAdapter { } dashKit = try DashKit.Kit( - seed: seed, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, - logger: logger + seed: seed, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, + logger: logger ) case let .hdExtendedKey(key): dashKit = try DashKit.Kit( - extendedKey: key, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, - logger: logger + extendedKey: key, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold, + logger: logger ) default: throw AdapterError.unsupportedAccount @@ -54,11 +54,9 @@ class DashAdapter: BitcoinBaseAdapter { override func explorerUrl(transactionHash: String) -> String? { "https://insight.dash.org/insight/tx/" + transactionHash } - } extension DashAdapter: DashKitDelegate { - public func transactionsUpdated(inserted: [DashTransactionInfo], updated: [DashTransactionInfo]) { var records = [BitcoinTransactionRecord]() @@ -71,21 +69,16 @@ extension DashAdapter: DashKitDelegate { transactionRecordsSubject.onNext(records) } - } extension DashAdapter: ISendBitcoinAdapter { - var blockchainType: BlockchainType { .dash } - } extension DashAdapter { - static func clear(except excludedWalletIds: [String]) throws { try Kit.clear(exceptFor: excludedWalletIds) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ECashAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ECashAdapter.swift index d97f9546e4..152f361ee9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ECashAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ECashAdapter.swift @@ -1,9 +1,9 @@ -import Foundation import BitcoinCore -import RxSwift -import MarketKit -import HdWalletKit import ECashKit +import Foundation +import HdWalletKit +import MarketKit +import RxSwift class ECashAdapter: BitcoinBaseAdapter { private static let eCashConfirmationsThreshold = 1 @@ -22,21 +22,21 @@ class ECashAdapter: BitcoinBaseAdapter { } eCashKit = try ECashKit.Kit( - seed: seed, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: Self.eCashConfirmationsThreshold, - logger: logger + seed: seed, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: Self.eCashConfirmationsThreshold, + logger: logger ) case let .hdExtendedKey(key): eCashKit = try ECashKit.Kit( - extendedKey: key, - walletId: wallet.account.id, - syncMode: syncMode, - networkType: networkType, - confirmationsThreshold: Self.eCashConfirmationsThreshold, - logger: logger + extendedKey: key, + walletId: wallet.account.id, + syncMode: syncMode, + networkType: networkType, + confirmationsThreshold: Self.eCashConfirmationsThreshold, + logger: logger ) default: throw AdapterError.unsupportedAccount @@ -54,21 +54,16 @@ class ECashAdapter: BitcoinBaseAdapter { override func explorerUrl(transactionHash: String) -> String? { "https://blockchair.com/ecash/transaction/" + transactionHash } - } extension ECashAdapter: ISendBitcoinAdapter { - var blockchainType: BlockchainType { .ecash } - } extension ECashAdapter { - static func clear(except excludedWalletIds: [String]) throws { try Kit.clear(exceptFor: excludedWalletIds) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/BaseEvmAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/BaseEvmAdapter.swift index 43e8ffe048..f1d262f455 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/BaseEvmAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/BaseEvmAdapter.swift @@ -1,8 +1,8 @@ -import Foundation -import EvmKit -import RxSwift import BigInt +import EvmKit +import Foundation import HsToolKit +import RxSwift class BaseEvmAdapter { static let confirmationsThreshold = 12 @@ -20,7 +20,7 @@ class BaseEvmAdapter { } func balanceDecimal(kitBalance: BigUInt?, decimals: Int) -> Decimal { - guard let kitBalance = kitBalance else { + guard let kitBalance else { return 0 } @@ -33,9 +33,9 @@ class BaseEvmAdapter { func convertToAdapterState(evmSyncState: EvmKit.SyncState) -> AdapterState { switch evmSyncState { - case .synced: return .synced - case .notSynced(let error): return .notSynced(error: error.convertedError) - case .syncing: return .syncing(progress: nil, lastBlockDate: nil) + case .synced: return .synced + case let .notSynced(error): return .notSynced(error: error.convertedError) + case .syncing: return .syncing(progress: nil, lastBlockDate: nil) } } @@ -46,12 +46,10 @@ class BaseEvmAdapter { func balanceData(balance: BigUInt?) -> BalanceData { BalanceData(available: balanceDecimal(kitBalance: balance, decimals: decimals)) } - } // IAdapter extension BaseEvmAdapter { - var statusInfo: [(String, Any)] { evmKit.statusInfo() } @@ -59,12 +57,10 @@ extension BaseEvmAdapter { var debugInfo: String { evmKit.debugInfo } - } // ITransactionsAdapter extension BaseEvmAdapter { - var lastBlockInfo: LastBlockInfo? { evmKit.lastBlockHeight.map { LastBlockInfo(height: $0, timestamp: nil) } } @@ -72,13 +68,10 @@ extension BaseEvmAdapter { var lastBlockUpdatedObservable: Observable { evmKit.lastBlockHeightObservable.map { _ in () } } - } extension BaseEvmAdapter: IDepositAdapter { - var receiveAddress: DepositAddress { DepositAddress(evmKit.receiveAddress.eip55) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/Eip20Adapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/Eip20Adapter.swift index de0bcfe791..57f19a09da 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/Eip20Adapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/Eip20Adapter.swift @@ -1,10 +1,10 @@ -import Foundation -import EvmKit -import Eip20Kit -import RxSwift import BigInt +import Eip20Kit +import EvmKit +import Foundation import HsToolKit import MarketKit +import RxSwift class Eip20Adapter: BaseEvmAdapter { private static let approveConfirmationsThreshold: Int? = nil @@ -21,13 +21,11 @@ class Eip20Adapter: BaseEvmAdapter { super.init(evmKitWrapper: evmKitWrapper, decimals: wallet.decimals) } - } // IAdapter extension Eip20Adapter: IAdapter { - func start() { eip20Kit.start() } @@ -36,13 +34,10 @@ extension Eip20Adapter: IAdapter { eip20Kit.stop() } - func refresh() { - } - + func refresh() {} } extension Eip20Adapter: IBalanceAdapter { - var balanceState: AdapterState { convertToAdapterState(evmSyncState: eip20Kit.syncState) } @@ -62,19 +57,15 @@ extension Eip20Adapter: IBalanceAdapter { self?.balanceData(balance: $0) ?? BalanceData(available: 0) } } - } extension Eip20Adapter: ISendEthereumAdapter { - func transactionData(amount: BigUInt, address: EvmKit.Address) -> TransactionData { eip20Kit.transferTransactionData(to: address, value: amount) } - } extension Eip20Adapter: IErc20Adapter { - var pendingTransactions: [TransactionRecord] { eip20Kit.pendingTransactions().map { transactionConverter.transactionRecord(fromTransaction: $0) } } @@ -83,13 +74,12 @@ extension Eip20Adapter: IErc20Adapter { let decimals = decimals return eip20Kit.allowanceSingle(spenderAddress: spenderAddress, defaultBlockParameter: defaultBlockParameter) - .map { allowanceString in - if let significand = Decimal(string: allowanceString) { - return Decimal(sign: .plus, exponent: -decimals, significand: significand) - } - - return 0 + .map { allowanceString in + if let significand = Decimal(string: allowanceString) { + return Decimal(sign: .plus, exponent: -decimals, significand: significand) } - } + return 0 + } + } } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmAdapter.swift index c11aa0f631..e849104e0a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmAdapter.swift @@ -1,8 +1,8 @@ -import EvmKit -import RxSwift import BigInt -import HsToolKit import Eip20Kit +import EvmKit +import HsToolKit +import RxSwift import UniswapKit class EvmAdapter: BaseEvmAdapter { @@ -11,20 +11,16 @@ class EvmAdapter: BaseEvmAdapter { init(evmKitWrapper: EvmKitWrapper) { super.init(evmKitWrapper: evmKitWrapper, decimals: EvmAdapter.decimals) } - } extension EvmAdapter { - static func clear(except excludedWalletIds: [String]) throws { try EvmKit.Kit.clear(exceptFor: excludedWalletIds) } - } // IAdapter extension EvmAdapter: IAdapter { - func start() { // started via EvmKitManager } @@ -36,11 +32,9 @@ extension EvmAdapter: IAdapter { func refresh() { // refreshed via EvmKitManager } - } extension EvmAdapter: IBalanceAdapter { - var balanceState: AdapterState { convertToAdapterState(evmSyncState: evmKit.syncState) } @@ -60,13 +54,10 @@ extension EvmAdapter: IBalanceAdapter { self?.balanceData(balance: $0.balance) ?? BalanceData(available: 0) } } - } extension EvmAdapter: ISendEthereumAdapter { - func transactionData(amount: BigUInt, address: EvmKit.Address) -> TransactionData { evmKit.transferTransactionData(to: address, value: amount) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionConverter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionConverter.swift index 386ce559dd..fbff54d4e1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionConverter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionConverter.swift @@ -1,11 +1,11 @@ -import Foundation -import EvmKit +import BigInt import Eip20Kit +import EvmKit +import Foundation +import MarketKit import NftKit -import UniswapKit import OneInchKit -import MarketKit -import BigInt +import UniswapKit class EvmTransactionConverter { private let coinManager: CoinManager @@ -45,7 +45,7 @@ class EvmTransactionConverter { if let token = try? coinManager.token(query: query) { let value = convertAmount(amount: value, decimals: token.decimals, sign: sign) return .coinValue(token: token, value: value) - } else if let tokenInfo = tokenInfo { + } else if let tokenInfo { let value = convertAmount(amount: value, decimals: tokenInfo.tokenDecimal, sign: sign) return .tokenValue(tokenName: tokenInfo.tokenName, tokenCode: tokenInfo.tokenSymbol, tokenDecimals: tokenInfo.tokenDecimal, value: value) } @@ -55,37 +55,37 @@ class EvmTransactionConverter { private func convertToAmount(token: SwapDecoration.Token, amount: SwapDecoration.Amount, sign: FloatingPointSign) -> SwapTransactionRecord.Amount { switch amount { - case .exact(let value): return .exact(value: convertToTransactionValue(token: token, value: value, sign: sign)) - case .extremum(let value): return .extremum(value: convertToTransactionValue(token: token, value: value, sign: sign)) + case let .exact(value): return .exact(value: convertToTransactionValue(token: token, value: value, sign: sign)) + case let .extremum(value): return .extremum(value: convertToTransactionValue(token: token, value: value, sign: sign)) } } private func convertToTransactionValue(token: SwapDecoration.Token, value: BigUInt, sign: FloatingPointSign) -> TransactionValue { switch token { case .evmCoin: return baseCoinValue(value: value, sign: sign) - case .eip20Coin(let tokenAddress, let tokenInfo): return eip20Value(tokenAddress: tokenAddress, value: value, sign: sign, tokenInfo: tokenInfo) + case let .eip20Coin(tokenAddress, tokenInfo): return eip20Value(tokenAddress: tokenAddress, value: value, sign: sign, tokenInfo: tokenInfo) } } private func convertToAmount(token: OneInchDecoration.Token, amount: OneInchDecoration.Amount, sign: FloatingPointSign) -> SwapTransactionRecord.Amount { switch amount { - case .exact(let value): return .exact(value: convertToTransactionValue(token: token, value: value, sign: sign)) - case .extremum(let value): return .extremum(value: convertToTransactionValue(token: token, value: value, sign: sign)) + case let .exact(value): return .exact(value: convertToTransactionValue(token: token, value: value, sign: sign)) + case let .extremum(value): return .extremum(value: convertToTransactionValue(token: token, value: value, sign: sign)) } } private func convertToTransactionValue(token: OneInchDecoration.Token, value: BigUInt, sign: FloatingPointSign) -> TransactionValue { switch token { case .evmCoin: return baseCoinValue(value: value, sign: sign) - case .eip20Coin(let tokenAddress, let tokenInfo): return eip20Value(tokenAddress: tokenAddress, value: value, sign: sign, tokenInfo: tokenInfo) + case let .eip20Coin(tokenAddress, tokenInfo): return eip20Value(tokenAddress: tokenAddress, value: value, sign: sign, tokenInfo: tokenInfo) } } private func transferEvents(incomingEip20Transfers: [TransferEventInstance]) -> [ContractCallTransactionRecord.TransferEvent] { incomingEip20Transfers.map { transfer in ContractCallTransactionRecord.TransferEvent( - address: transfer.from.eip55, - value: eip20Value(tokenAddress: transfer.contractAddress, value: transfer.value, sign: .plus, tokenInfo: transfer.tokenInfo) + address: transfer.from.eip55, + value: eip20Value(tokenAddress: transfer.contractAddress, value: transfer.value, sign: .plus, tokenInfo: transfer.tokenInfo) ) } } @@ -93,8 +93,8 @@ class EvmTransactionConverter { private func transferEvents(outgoingEip20Transfers: [TransferEventInstance]) -> [ContractCallTransactionRecord.TransferEvent] { outgoingEip20Transfers.map { transfer in ContractCallTransactionRecord.TransferEvent( - address: transfer.to.eip55, - value: eip20Value(tokenAddress: transfer.contractAddress, value: transfer.value, sign: .minus, tokenInfo: transfer.tokenInfo) + address: transfer.to.eip55, + value: eip20Value(tokenAddress: transfer.contractAddress, value: transfer.value, sign: .minus, tokenInfo: transfer.tokenInfo) ) } } @@ -102,13 +102,13 @@ class EvmTransactionConverter { private func transferEvents(incomingEip721Transfers: [Eip721TransferEventInstance]) -> [ContractCallTransactionRecord.TransferEvent] { incomingEip721Transfers.map { transfer in ContractCallTransactionRecord.TransferEvent( - address: transfer.from.eip55, - value: .nftValue( - nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), - value: 1, - tokenName: transfer.tokenInfo?.tokenName, - tokenSymbol: transfer.tokenInfo?.tokenSymbol - ) + address: transfer.from.eip55, + value: .nftValue( + nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), + value: 1, + tokenName: transfer.tokenInfo?.tokenName, + tokenSymbol: transfer.tokenInfo?.tokenSymbol + ) ) } } @@ -116,13 +116,13 @@ class EvmTransactionConverter { private func transferEvents(outgoingEip721Transfers: [Eip721TransferEventInstance]) -> [ContractCallTransactionRecord.TransferEvent] { outgoingEip721Transfers.map { transfer in ContractCallTransactionRecord.TransferEvent( - address: transfer.to.eip55, - value: .nftValue( - nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), - value: -1, - tokenName: transfer.tokenInfo?.tokenName, - tokenSymbol: transfer.tokenInfo?.tokenSymbol - ) + address: transfer.to.eip55, + value: .nftValue( + nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), + value: -1, + tokenName: transfer.tokenInfo?.tokenName, + tokenSymbol: transfer.tokenInfo?.tokenSymbol + ) ) } } @@ -130,13 +130,13 @@ class EvmTransactionConverter { private func transferEvents(incomingEip1155Transfers: [Eip1155TransferEventInstance]) -> [ContractCallTransactionRecord.TransferEvent] { incomingEip1155Transfers.map { transfer in ContractCallTransactionRecord.TransferEvent( - address: transfer.from.eip55, - value: .nftValue( - nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), - value: convertAmount(amount: transfer.value, decimals: 0, sign: .plus), - tokenName: transfer.tokenInfo?.tokenName, - tokenSymbol: transfer.tokenInfo?.tokenSymbol - ) + address: transfer.from.eip55, + value: .nftValue( + nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), + value: convertAmount(amount: transfer.value, decimals: 0, sign: .plus), + tokenName: transfer.tokenInfo?.tokenName, + tokenSymbol: transfer.tokenInfo?.tokenSymbol + ) ) } } @@ -144,13 +144,13 @@ class EvmTransactionConverter { private func transferEvents(outgoingEip1155Transfers: [Eip1155TransferEventInstance]) -> [ContractCallTransactionRecord.TransferEvent] { outgoingEip1155Transfers.map { transfer in ContractCallTransactionRecord.TransferEvent( - address: transfer.to.eip55, - value: .nftValue( - nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), - value: convertAmount(amount: transfer.value, decimals: 0, sign: .minus), - tokenName: transfer.tokenInfo?.tokenName, - tokenSymbol: transfer.tokenInfo?.tokenSymbol - ) + address: transfer.to.eip55, + value: .nftValue( + nftUid: .evm(blockchainType: source.blockchainType, contractAddress: transfer.contractAddress.hex, tokenId: transfer.tokenId.description), + value: convertAmount(amount: transfer.value, decimals: 0, sign: .minus), + tokenName: transfer.tokenInfo?.tokenName, + tokenSymbol: transfer.tokenInfo?.tokenSymbol + ) ) } } @@ -158,8 +158,8 @@ class EvmTransactionConverter { private func transferEvents(internalTransactions: [InternalTransaction]) -> [ContractCallTransactionRecord.TransferEvent] { internalTransactions.map { internalTransaction in ContractCallTransactionRecord.TransferEvent( - address: internalTransaction.from.eip55, - value: baseCoinValue(value: internalTransaction.value, sign: .plus) + address: internalTransaction.from.eip55, + value: baseCoinValue(value: internalTransaction.value, sign: .plus) ) } } @@ -170,137 +170,135 @@ class EvmTransactionConverter { } let event = ContractCallTransactionRecord.TransferEvent( - address: contractAddress.eip55, - value: baseCoinValue(value: value, sign: .minus) + address: contractAddress.eip55, + value: baseCoinValue(value: value, sign: .minus) ) return [event] } - } extension EvmTransactionConverter { - func transactionRecord(fromTransaction fullTransaction: FullTransaction) -> EvmTransactionRecord { let transaction = fullTransaction.transaction switch fullTransaction.decoration { case is ContractCreationDecoration: return ContractCreationTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken + source: source, + transaction: transaction, + baseToken: baseToken ) case let decoration as IncomingDecoration: return EvmIncomingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - from: decoration.from.eip55, - value: baseCoinValue(value: decoration.value, sign: .plus) + source: source, + transaction: transaction, + baseToken: baseToken, + from: decoration.from.eip55, + value: baseCoinValue(value: decoration.value, sign: .plus) ) case let decoration as OutgoingDecoration: return EvmOutgoingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - to: decoration.to.eip55, - value: baseCoinValue(value: decoration.value, sign: .minus), - sentToSelf: decoration.sentToSelf + source: source, + transaction: transaction, + baseToken: baseToken, + to: decoration.to.eip55, + value: baseCoinValue(value: decoration.value, sign: .minus), + sentToSelf: decoration.sentToSelf ) case let decoration as OutgoingEip20Decoration: return EvmOutgoingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - to: decoration.to.eip55, - value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .minus, tokenInfo: decoration.tokenInfo), - sentToSelf: decoration.sentToSelf + source: source, + transaction: transaction, + baseToken: baseToken, + to: decoration.to.eip55, + value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .minus, tokenInfo: decoration.tokenInfo), + sentToSelf: decoration.sentToSelf ) case let decoration as ApproveEip20Decoration: return ApproveTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - spender: decoration.spender.eip55, - value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .plus, tokenInfo: nil) + source: source, + transaction: transaction, + baseToken: baseToken, + spender: decoration.spender.eip55, + value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .plus, tokenInfo: nil) ) case let decoration as SwapDecoration: return SwapTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - exchangeAddress: decoration.contractAddress.eip55, - amountIn: convertToAmount(token: decoration.tokenIn, amount: decoration.amountIn, sign: .minus), - amountOut: convertToAmount(token: decoration.tokenOut, amount: decoration.amountOut, sign: .plus), - recipient: decoration.recipient?.eip55 + source: source, + transaction: transaction, + baseToken: baseToken, + exchangeAddress: decoration.contractAddress.eip55, + amountIn: convertToAmount(token: decoration.tokenIn, amount: decoration.amountIn, sign: .minus), + amountOut: convertToAmount(token: decoration.tokenOut, amount: decoration.amountOut, sign: .plus), + recipient: decoration.recipient?.eip55 ) case let decoration as OneInchSwapDecoration: return SwapTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - exchangeAddress: decoration.contractAddress.eip55, - amountIn: .exact(value: convertToTransactionValue(token: decoration.tokenIn, value: decoration.amountIn, sign: .minus)), - amountOut: convertToAmount(token: decoration.tokenOut, amount: decoration.amountOut, sign: .plus), - recipient: decoration.recipient?.eip55 + source: source, + transaction: transaction, + baseToken: baseToken, + exchangeAddress: decoration.contractAddress.eip55, + amountIn: .exact(value: convertToTransactionValue(token: decoration.tokenIn, value: decoration.amountIn, sign: .minus)), + amountOut: convertToAmount(token: decoration.tokenOut, amount: decoration.amountOut, sign: .plus), + recipient: decoration.recipient?.eip55 ) case let decoration as OneInchUnoswapDecoration: return SwapTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - exchangeAddress: decoration.contractAddress.eip55, - amountIn: .exact(value: convertToTransactionValue(token: decoration.tokenIn, value: decoration.amountIn, sign: .minus)), - amountOut: decoration.tokenOut.map { convertToAmount(token: $0, amount: decoration.amountOut, sign: .plus) }, - recipient: nil + source: source, + transaction: transaction, + baseToken: baseToken, + exchangeAddress: decoration.contractAddress.eip55, + amountIn: .exact(value: convertToTransactionValue(token: decoration.tokenIn, value: decoration.amountIn, sign: .minus)), + amountOut: decoration.tokenOut.map { convertToAmount(token: $0, amount: decoration.amountOut, sign: .plus) }, + recipient: nil ) case let decoration as OneInchUnknownSwapDecoration: return UnknownSwapTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - exchangeAddress: decoration.contractAddress.eip55, - valueIn: decoration.tokenAmountIn.map { convertToTransactionValue(token: $0.token, value: $0.value, sign: .minus) }, - valueOut: decoration.tokenAmountOut.map { convertToTransactionValue(token: $0.token, value: $0.value, sign: .plus) } + source: source, + transaction: transaction, + baseToken: baseToken, + exchangeAddress: decoration.contractAddress.eip55, + valueIn: decoration.tokenAmountIn.map { convertToTransactionValue(token: $0.token, value: $0.value, sign: .minus) }, + valueOut: decoration.tokenAmountOut.map { convertToTransactionValue(token: $0.token, value: $0.value, sign: .plus) } ) case let decoration as Eip721SafeTransferFromDecoration: return EvmOutgoingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - to: decoration.to.eip55, - value: .nftValue( - nftUid: .evm(blockchainType: source.blockchainType, contractAddress: decoration.contractAddress.hex, tokenId: decoration.tokenId.description), - value: convertAmount(amount: 1, decimals: 0, sign: .minus), - tokenName: decoration.tokenInfo?.tokenName, - tokenSymbol: decoration.tokenInfo?.tokenSymbol - ), - sentToSelf: decoration.sentToSelf + source: source, + transaction: transaction, + baseToken: baseToken, + to: decoration.to.eip55, + value: .nftValue( + nftUid: .evm(blockchainType: source.blockchainType, contractAddress: decoration.contractAddress.hex, tokenId: decoration.tokenId.description), + value: convertAmount(amount: 1, decimals: 0, sign: .minus), + tokenName: decoration.tokenInfo?.tokenName, + tokenSymbol: decoration.tokenInfo?.tokenSymbol + ), + sentToSelf: decoration.sentToSelf ) case let decoration as Eip1155SafeTransferFromDecoration: return EvmOutgoingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - to: decoration.to.eip55, - value: .nftValue( - nftUid: .evm(blockchainType: source.blockchainType, contractAddress: decoration.contractAddress.hex, tokenId: decoration.tokenId.description), - value: convertAmount(amount: decoration.value, decimals: 0, sign: .minus), - tokenName: decoration.tokenInfo?.tokenName, - tokenSymbol: decoration.tokenInfo?.tokenSymbol - ), - sentToSelf: decoration.sentToSelf + source: source, + transaction: transaction, + baseToken: baseToken, + to: decoration.to.eip55, + value: .nftValue( + nftUid: .evm(blockchainType: source.blockchainType, contractAddress: decoration.contractAddress.hex, tokenId: decoration.tokenId.description), + value: convertAmount(amount: decoration.value, decimals: 0, sign: .minus), + tokenName: decoration.tokenInfo?.tokenName, + tokenSymbol: decoration.tokenInfo?.tokenSymbol + ), + sentToSelf: decoration.sentToSelf ) case let decoration as UnknownTransactionDecoration: @@ -322,25 +320,25 @@ extension EvmTransactionConverter { if transaction.from == address, let contractAddress = transaction.to, let value = transaction.value { return ContractCallTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - contractAddress: contractAddress.eip55, - method: transaction.input.flatMap { evmLabelManager.methodLabel(input: $0) }, - incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingEip20Transfers: incomingEip20Transfers) + - transferEvents(incomingEip721Transfers: incomingEip721Transfers) + transferEvents(incomingEip1155Transfers: incomingEip1155Transfers), - outgoingEvents: transferEvents(contractAddress: contractAddress, value: value) + transferEvents(outgoingEip20Transfers: outgoingEip20Transfers) + - transferEvents(outgoingEip721Transfers: outgoingEip721Transfers) + transferEvents(outgoingEip1155Transfers: outgoingEip1155Transfers) + source: source, + transaction: transaction, + baseToken: baseToken, + contractAddress: contractAddress.eip55, + method: transaction.input.flatMap { evmLabelManager.methodLabel(input: $0) }, + incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingEip20Transfers: incomingEip20Transfers) + + transferEvents(incomingEip721Transfers: incomingEip721Transfers) + transferEvents(incomingEip1155Transfers: incomingEip1155Transfers), + outgoingEvents: transferEvents(contractAddress: contractAddress, value: value) + transferEvents(outgoingEip20Transfers: outgoingEip20Transfers) + + transferEvents(outgoingEip721Transfers: outgoingEip721Transfers) + transferEvents(outgoingEip1155Transfers: outgoingEip1155Transfers) ) - } else if transaction.from != address && transaction.to != address { + } else if transaction.from != address, transaction.to != address { return ExternalContractCallTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingEip20Transfers: incomingEip20Transfers) + - transferEvents(incomingEip721Transfers: incomingEip721Transfers) + transferEvents(incomingEip1155Transfers: incomingEip1155Transfers), - outgoingEvents: transferEvents(outgoingEip20Transfers: outgoingEip20Transfers) + - transferEvents(outgoingEip721Transfers: outgoingEip721Transfers) + transferEvents(outgoingEip1155Transfers: outgoingEip1155Transfers) + source: source, + transaction: transaction, + baseToken: baseToken, + incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingEip20Transfers: incomingEip20Transfers) + + transferEvents(incomingEip721Transfers: incomingEip721Transfers) + transferEvents(incomingEip1155Transfers: incomingEip1155Transfers), + outgoingEvents: transferEvents(outgoingEip20Transfers: outgoingEip20Transfers) + + transferEvents(outgoingEip721Transfers: outgoingEip721Transfers) + transferEvents(outgoingEip1155Transfers: outgoingEip1155Transfers) ) } @@ -348,11 +346,10 @@ extension EvmTransactionConverter { } return EvmTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - ownTransaction: transaction.from == evmKit.address + source: source, + transaction: transaction, + baseToken: baseToken, + ownTransaction: transaction.from == evmKit.address ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionsAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionsAdapter.swift index 4c82f2402f..eedc5e262d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionsAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Evm/EvmTransactionsAdapter.swift @@ -1,11 +1,11 @@ -import Foundation -import EvmKit -import RxSwift import BigInt -import HsToolKit import Eip20Kit -import UniswapKit +import EvmKit +import Foundation +import HsToolKit import MarketKit +import RxSwift +import UniswapKit class EvmTransactionsAdapter: BaseEvmAdapter { static let decimal = 18 @@ -25,11 +25,11 @@ class EvmTransactionsAdapter: BaseEvmAdapter { var `protocol`: TransactionTag.TagProtocol? var contractAddress: EvmKit.Address? - if let token = token { + if let token { switch token.type { case .native: `protocol` = .native - case .eip20(let address): + case let .eip20(address): if let address = try? EvmKit.Address(hex: address) { `protocol` = .eip20 contractAddress = address @@ -48,7 +48,6 @@ class EvmTransactionsAdapter: BaseEvmAdapter { return TransactionTagQuery(type: type, protocol: `protocol`, contractAddress: contractAddress) } - } extension EvmTransactionsAdapter: ITransactionsAdapter { @@ -56,7 +55,7 @@ extension EvmTransactionsAdapter: ITransactionsAdapter { evmKit.transactionsSyncState.syncing } - var syncingObservable: Observable<()> { + var syncingObservable: Observable { evmKit.transactionsSyncStateObservable.map { _ in () } } @@ -76,13 +75,12 @@ extension EvmTransactionsAdapter: ITransactionsAdapter { func transactionsSingle(from: TransactionRecord?, token: MarketKit.Token?, filter: TransactionTypeFilter, limit: Int) -> Single<[TransactionRecord]> { evmKit.transactionsSingle(tagQueries: [tagQuery(token: token, filter: filter)], fromHash: from.flatMap { Data(hex: $0.transactionHash) }, limit: limit) - .map { [weak self] transactions -> [TransactionRecord] in - transactions.compactMap { self?.transactionConverter.transactionRecord(fromTransaction: $0) } - } + .map { [weak self] transactions -> [TransactionRecord] in + transactions.compactMap { self?.transactionConverter.transactionRecord(fromTransaction: $0) } + } } - func rawTransaction(hash: String) -> String? { + func rawTransaction(hash _: String) -> String? { nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Nft/EvmNftAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Nft/EvmNftAdapter.swift index ea31c4b3f0..7f27c641e2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Nft/EvmNftAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Nft/EvmNftAdapter.swift @@ -1,9 +1,9 @@ +import BigInt +import EvmKit import Foundation -import RxSwift -import NftKit import MarketKit -import EvmKit -import BigInt +import NftKit +import RxSwift class EvmNftAdapter { private let blockchainType: BlockchainType @@ -18,28 +18,26 @@ class EvmNftAdapter { private func record(nftBalance: NftBalance) -> EvmNftRecord { EvmNftRecord( - blockchainType: blockchainType, - type: nftBalance.nft.type, - contractAddress: nftBalance.nft.contractAddress.hex, - tokenId: nftBalance.nft.tokenId.description, - tokenName: nftBalance.nft.tokenName, - balance: nftBalance.balance + blockchainType: blockchainType, + type: nftBalance.nft.type, + contractAddress: nftBalance.nft.contractAddress.hex, + tokenId: nftBalance.nft.tokenId.description, + tokenName: nftBalance.nft.tokenName, + balance: nftBalance.balance ) } - } extension EvmNftAdapter: INftAdapter { - var userAddress: String { evmKitWrapper.evmKit.address.hex } var nftRecordsObservable: Observable<[NftRecord]> { nftKit.nftBalancesObservable - .map { [weak self] nftBalances in - nftBalances.compactMap { self?.record(nftBalance: $0) } - } + .map { [weak self] nftBalances in + nftBalances.compactMap { self?.record(nftBalance: $0) } + } } var nftRecords: [NftRecord] { @@ -93,13 +91,10 @@ extension EvmNftAdapter: INftAdapter { func sync() { nftKit.sync() } - } extension EvmNftAdapter { - static func clear(except excludedWalletIds: [String]) throws { try NftKit.Kit.clear(exceptFor: excludedWalletIds) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/BaseTronAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/BaseTronAdapter.swift index 106883f427..c69b8efde6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/BaseTronAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/BaseTronAdapter.swift @@ -1,8 +1,8 @@ -import Foundation -import TronKit -import RxSwift import BigInt +import Foundation import HsToolKit +import RxSwift +import TronKit class BaseTronAdapter { static let confirmationsThreshold = 18 @@ -20,7 +20,7 @@ class BaseTronAdapter { } func balanceDecimal(kitBalance: BigUInt?, decimals: Int) -> Decimal { - guard let kitBalance = kitBalance else { + guard let kitBalance else { return 0 } @@ -33,9 +33,9 @@ class BaseTronAdapter { func convertToAdapterState(tronSyncState: TronKit.SyncState) -> AdapterState { switch tronSyncState { - case .synced: return .synced - case .notSynced(let error): return .notSynced(error: error.convertedError) - case .syncing: return .syncing(progress: nil, lastBlockDate: nil) + case .synced: return .synced + case let .notSynced(error): return .notSynced(error: error.convertedError) + case .syncing: return .syncing(progress: nil, lastBlockDate: nil) } } @@ -48,14 +48,12 @@ class BaseTronAdapter { } func accountActive(address: TronKit.Address) async -> Bool { - return (try? await tronKit.accountActive(address: address)) ?? true + await (try? tronKit.accountActive(address: address)) ?? true } - } // IAdapter extension BaseTronAdapter { - var statusInfo: [(String, Any)] { [] } @@ -63,12 +61,10 @@ extension BaseTronAdapter { var debugInfo: String { "" } - } // ITransactionsAdapter extension BaseTronAdapter { - var lastBlockInfo: LastBlockInfo? { tronKit.lastBlockHeight.map { LastBlockInfo(height: $0, timestamp: nil) } } @@ -76,16 +72,13 @@ extension BaseTronAdapter { var lastBlockUpdatedObservable: Observable { tronKit.lastBlockHeightPublisher.asObservable().map { _ in () } } - } extension BaseTronAdapter: IDepositAdapter { - var receiveAddress: DepositAddress { ActivatedDepositAddress( receiveAddress: tronKit.receiveAddress.base58, isActive: tronKit.accountActive ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/Trc20Adapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/Trc20Adapter.swift index 4510a3dc2f..b7e0e16ed7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/Trc20Adapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/Trc20Adapter.swift @@ -1,9 +1,9 @@ -import Foundation -import TronKit -import RxSwift import BigInt +import Foundation import HsToolKit import MarketKit +import RxSwift +import TronKit class Trc20Adapter: BaseTronAdapter { private let contractAddress: TronKit.Address @@ -13,12 +13,10 @@ class Trc20Adapter: BaseTronAdapter { super.init(tronKitWrapper: tronKitWrapper, decimals: wallet.decimals) } - } // IAdapter extension Trc20Adapter: IAdapter { - func start() { // started via TronKitManager } @@ -30,11 +28,9 @@ extension Trc20Adapter: IAdapter { func refresh() { // refreshed via TronKitManager } - } extension Trc20Adapter: IBalanceAdapter { - var balanceState: AdapterState { convertToAdapterState(tronSyncState: tronKit.syncState) } @@ -54,13 +50,10 @@ extension Trc20Adapter: IBalanceAdapter { self?.balanceData(balance: $0) ?? BalanceData(available: 0) } } - } extension Trc20Adapter: ISendTronAdapter { - func contract(amount: BigUInt, address: TronKit.Address) -> Contract { tronKit.transferTrc20TriggerSmartContract(contractAddress: contractAddress, toAddress: address, amount: amount) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronAdapter.swift index c177f8d359..0bc589670f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronAdapter.swift @@ -1,7 +1,7 @@ -import TronKit -import RxSwift import BigInt import HsToolKit +import RxSwift +import TronKit class TronAdapter: BaseTronAdapter { static let decimals = 6 @@ -9,20 +9,16 @@ class TronAdapter: BaseTronAdapter { init(tronKitWrapper: TronKitWrapper) { super.init(tronKitWrapper: tronKitWrapper, decimals: TronAdapter.decimals) } - } extension TronAdapter { - static func clear(except excludedWalletIds: [String]) throws { try TronKit.Kit.clear(exceptFor: excludedWalletIds) } - } // IAdapter extension TronAdapter: IAdapter { - func start() { // started via TronKitManager } @@ -34,11 +30,9 @@ extension TronAdapter: IAdapter { func refresh() { // refreshed via TronKitManager } - } extension TronAdapter: IBalanceAdapter { - var balanceState: AdapterState { convertToAdapterState(tronSyncState: tronKit.syncState) } @@ -58,13 +52,10 @@ extension TronAdapter: IBalanceAdapter { self?.balanceData(balance: $0) ?? BalanceData(available: 0) } } - } extension TronAdapter: ISendTronAdapter { - func contract(amount: BigUInt, address: TronKit.Address) -> Contract { tronKit.transferContract(toAddress: address, value: Int(amount)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionAdapter.swift index 5979fa29b2..26d740826e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionAdapter.swift @@ -1,9 +1,9 @@ -import Foundation -import TronKit -import RxSwift import BigInt +import Foundation import HsToolKit import MarketKit +import RxSwift +import TronKit class TronTransactionsAdapter: BaseTronAdapter { static let decimal = 6 @@ -21,30 +21,29 @@ class TronTransactionsAdapter: BaseTronAdapter { var `protocol`: TransactionTag.TagProtocol? var contractAddress: TronKit.Address? - if let token = token { + if let token { switch token.type { - case .native: - `protocol` = .native - case .eip20(let address): - if let address = try? TronKit.Address(address: address) { - `protocol` = .eip20 - contractAddress = address - } - default: () + case .native: + `protocol` = .native + case let .eip20(address): + if let address = try? TronKit.Address(address: address) { + `protocol` = .eip20 + contractAddress = address + } + default: () } } switch filter { - case .all: () - case .incoming: type = .incoming - case .outgoing: type = .outgoing - case .swap: type = .swap - case .approve: type = .approve + case .all: () + case .incoming: type = .incoming + case .outgoing: type = .outgoing + case .swap: type = .swap + case .approve: type = .approve } return TransactionTagQuery(type: type, protocol: `protocol`, contractAddress: contractAddress) } - } extension TronTransactionsAdapter: ITransactionsAdapter { @@ -52,7 +51,7 @@ extension TronTransactionsAdapter: ITransactionsAdapter { tronKit.syncState.syncing } - var syncingObservable: Observable<()> { + var syncingObservable: Observable { tronKit.syncStatePublisher.asObservable().map { _ in () } } @@ -62,9 +61,9 @@ extension TronTransactionsAdapter: ITransactionsAdapter { func explorerUrl(transactionHash: String) -> String? { switch tronKit.network { - case .mainNet: return "https://tronscan.org/#/transaction/\(transactionHash)" - case .nileTestnet: return "https://nile.tronscan.org/#/transaction/\(transactionHash)" - case .shastaTestnet: return "https://shasta.tronscan.org/#/transaction/\(transactionHash)" + case .mainNet: return "https://tronscan.org/#/transaction/\(transactionHash)" + case .nileTestnet: return "https://nile.tronscan.org/#/transaction/\(transactionHash)" + case .shastaTestnet: return "https://shasta.tronscan.org/#/transaction/\(transactionHash)" } } @@ -81,10 +80,9 @@ extension TronTransactionsAdapter: ITransactionsAdapter { return Single.just(transactions.compactMap { transactionConverter.transactionRecord(fromTransaction: $0) }) } - func rawTransaction(hash: String) -> String? { + func rawTransaction(hash _: String) -> String? { nil } - } class ActivatedDepositAddress: DepositAddress { diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionConverter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionConverter.swift index d3e9e26e14..219d2c2cbd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionConverter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/Tron/TronTransactionConverter.swift @@ -1,7 +1,7 @@ +import BigInt import Foundation -import TronKit import MarketKit -import BigInt +import TronKit class TronTransactionConverter { private let coinManager: CoinManager @@ -41,7 +41,7 @@ class TronTransactionConverter { if let token = try? coinManager.token(query: query) { let value = convertAmount(amount: value, decimals: token.decimals, sign: sign) return .coinValue(token: token, value: value) - } else if let tokenInfo = tokenInfo { + } else if let tokenInfo { let value = convertAmount(amount: value, decimals: tokenInfo.tokenDecimal, sign: sign) return .tokenValue(tokenName: tokenInfo.tokenName, tokenCode: tokenInfo.tokenSymbol, tokenDecimals: tokenInfo.tokenDecimal, value: value) } @@ -88,98 +88,96 @@ class TronTransactionConverter { return [event] } - } extension TronTransactionConverter { - func transactionRecord(fromTransaction fullTransaction: FullTransaction) -> TronTransactionRecord { let transaction = fullTransaction.transaction switch fullTransaction.decoration { - case let decoration as NativeTransactionDecoration: - switch decoration.contract { - case let transfer as TransferContract: - if transfer.ownerAddress != tronKit.address { - return TronIncomingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - from: transfer.ownerAddress.base58, - value: baseCoinValue(value: transfer.amount, sign: .plus), - spam: transfer.amount < 10 - ) - } else { - return TronOutgoingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - to: transfer.toAddress.base58, - value: baseCoinValue(value: transfer.amount, sign: .minus), - sentToSelf: transfer.toAddress == tronKit.address - ) - } - - default: - return TronTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - ownTransaction: transaction.ownTransaction(ownAddress: tronKit.address) - ) + case let decoration as NativeTransactionDecoration: + switch decoration.contract { + case let transfer as TransferContract: + if transfer.ownerAddress != tronKit.address { + return TronIncomingTransactionRecord( + source: source, + transaction: transaction, + baseToken: baseToken, + from: transfer.ownerAddress.base58, + value: baseCoinValue(value: transfer.amount, sign: .plus), + spam: transfer.amount < 10 + ) + } else { + return TronOutgoingTransactionRecord( + source: source, + transaction: transaction, + baseToken: baseToken, + to: transfer.toAddress.base58, + value: baseCoinValue(value: transfer.amount, sign: .minus), + sentToSelf: transfer.toAddress == tronKit.address + ) } - - case let decoration as OutgoingEip20Decoration: - return TronOutgoingTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - to: decoration.to.base58, - value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .minus, tokenInfo: decoration.tokenInfo), - sentToSelf: decoration.sentToSelf - ) - case let decoration as ApproveEip20Decoration: - return TronApproveTransactionRecord( + default: + return TronTransactionRecord( source: source, transaction: transaction, baseToken: baseToken, - spender: decoration.spender.base58, - value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .plus, tokenInfo: nil) + ownTransaction: transaction.ownTransaction(ownAddress: tronKit.address) ) + } + + case let decoration as OutgoingEip20Decoration: + return TronOutgoingTransactionRecord( + source: source, + transaction: transaction, + baseToken: baseToken, + to: decoration.to.base58, + value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .minus, tokenInfo: decoration.tokenInfo), + sentToSelf: decoration.sentToSelf + ) - case let decoration as UnknownTransactionDecoration: - let address = tronKit.address + case let decoration as ApproveEip20Decoration: + return TronApproveTransactionRecord( + source: source, + transaction: transaction, + baseToken: baseToken, + spender: decoration.spender.base58, + value: eip20Value(tokenAddress: decoration.contractAddress, value: decoration.value, sign: .plus, tokenInfo: nil) + ) - let internalTransactions = decoration.internalTransactions.filter { $0.to == address } + case let decoration as UnknownTransactionDecoration: + let address = tronKit.address - let trc0Transfers = decoration.events.compactMap { $0 as? Trc20TransferEvent } - let incomingTrc20Transfers = trc0Transfers.filter { $0.to == address && $0.from != address } - let outgoingTrc20Transfers = trc0Transfers.filter { $0.from == address } + let internalTransactions = decoration.internalTransactions.filter { $0.to == address } - if decoration.fromAddress == address, let contractAddress = decoration.toAddress { - let value = decoration.value ?? 0 + let trc0Transfers = decoration.events.compactMap { $0 as? Trc20TransferEvent } + let incomingTrc20Transfers = trc0Transfers.filter { $0.to == address && $0.from != address } + let outgoingTrc20Transfers = trc0Transfers.filter { $0.from == address } - return TronContractCallTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - contractAddress: contractAddress.base58, - method: decoration.data.flatMap { evmLabelManager.methodLabel(input: $0) }, - incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingTrc20Transfers: incomingTrc20Transfers), - outgoingEvents: transferEvents(contractAddress: contractAddress, value: value) + transferEvents(outgoingTrc20Transfers: outgoingTrc20Transfers) - ) - } else if decoration.fromAddress != address && decoration.toAddress != address { - return TronExternalContractCallTransactionRecord( - source: source, - transaction: transaction, - baseToken: baseToken, - incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingTrc20Transfers: incomingTrc20Transfers), - outgoingEvents: transferEvents(outgoingTrc20Transfers: outgoingTrc20Transfers) - ) - } + if decoration.fromAddress == address, let contractAddress = decoration.toAddress { + let value = decoration.value ?? 0 - default: () + return TronContractCallTransactionRecord( + source: source, + transaction: transaction, + baseToken: baseToken, + contractAddress: contractAddress.base58, + method: decoration.data.flatMap { evmLabelManager.methodLabel(input: $0) }, + incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingTrc20Transfers: incomingTrc20Transfers), + outgoingEvents: transferEvents(contractAddress: contractAddress, value: value) + transferEvents(outgoingTrc20Transfers: outgoingTrc20Transfers) + ) + } else if decoration.fromAddress != address, decoration.toAddress != address { + return TronExternalContractCallTransactionRecord( + source: source, + transaction: transaction, + baseToken: baseToken, + incomingEvents: transferEvents(internalTransactions: internalTransactions) + transferEvents(incomingTrc20Transfers: incomingTrc20Transfers), + outgoingEvents: transferEvents(outgoingTrc20Transfers: outgoingTrc20Transfers) + ) + } + + default: () } return TronTransactionRecord( @@ -189,5 +187,4 @@ extension TronTransactionConverter { ownTransaction: transaction.ownTransaction(ownAddress: tronKit.address) ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashAdapter.swift index d4ec54d612..f10e270bd8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashAdapter.swift @@ -74,7 +74,7 @@ class ZcashAdapter { network = ZcashNetworkBuilder.network(for: .mainnet) - // todo: update fee settings + // TODO: update fee settings fee = network.constants.defaultFee().decimalValue.decimalValue token = wallet.token @@ -83,7 +83,8 @@ class ZcashAdapter { var existingMode: WalletInitMode? if let dbUrl = try? Self.spendParamsURL(uniqueId: uniqueId), - Self.exist(url: dbUrl) { + Self.exist(url: dbUrl) + { existingMode = .existingWallet } switch wallet.account.origin { @@ -179,8 +180,8 @@ class ZcashAdapter { let shieldedVerified = await (try? synchronizer.getShieldedVerifiedBalance(accountIndex: 0).decimalValue.decimalValue) ?? 0 self?.balanceSubject.onNext( VerifiedBalanceData( - fullBalance: shielded, - available: shieldedVerified + fullBalance: shielded, + available: shieldedVerified ) ) let height = try await synchronizer.latestHeight() @@ -475,7 +476,7 @@ class ZcashAdapter { } private var _balanceData: BalanceData { - guard let synchronizerState = synchronizerState else { + guard let synchronizerState else { return BalanceData(available: 0) } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionPool.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionPool.swift index 7fccd05526..65dddd8638 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionPool.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionPool.swift @@ -22,7 +22,7 @@ class ZcashTransactionPool { confirmedTransactions = confirmedTransactions.filter { !$0.isSentTransaction } pendingTransactions = pendingTransactions.filter { !$0.isSentTransaction } case .outgoing: - confirmedTransactions = confirmedTransactions.filter { $0.isSentTransaction } + confirmedTransactions = confirmedTransactions.filter(\.isSentTransaction) pendingTransactions = pendingTransactions.filter { !$0.isSentTransaction } default: confirmedTransactions = [] @@ -43,14 +43,14 @@ class ZcashTransactionPool { } private func transactionWithAdditional(tx: ZcashTransaction.Overview, lastBlockHeight: Int) async throws -> ZcashTransactionWrapper? { - let memos: [Memo] = (try? await synchronizer.getMemos(for: tx)) ?? [] + let memos: [Memo] = await (try? synchronizer.getMemos(for: tx)) ?? [] let firstMemo = memos .compactMap { $0.toString() } .first let recipients = await synchronizer.getRecipients(for: tx) let firstAddress = recipients - .filter { $0.hasAddress } + .filter(\.hasAddress) .first return ZcashTransactionWrapper(tx: tx, memo: firstMemo, recipient: firstAddress, lastBlockHeight: lastBlockHeight) @@ -65,7 +65,7 @@ class ZcashTransactionPool { // let pending = await synchronizer.pendingTransactions // pendingTransactions = await Set(zcashTransactions(pending, lastBlockHeight: 0)) - confirmedTransactions = Set(await zcashTransactions(overviews, lastBlockHeight: 0)) + confirmedTransactions = await Set(zcashTransactions(overviews, lastBlockHeight: 0)) } func sync(transactions: [ZcashTransaction.Overview], lastBlockHeight: Int) async -> [ZcashTransactionWrapper] { diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionWrapper.swift b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionWrapper.swift index ea287a82ac..55217768d3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionWrapper.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Adapters/ZcashTransactionWrapper.swift @@ -1,6 +1,6 @@ import Foundation -import ZcashLightClientKit import HsExtensions +import ZcashLightClientKit class ZcashTransactionWrapper { let raw: Data? @@ -34,12 +34,10 @@ class ZcashTransactionWrapper { fee = tx.fee self.memo = memo } - } extension ZcashTransactionWrapper: Comparable { - - public static func <(lhs: ZcashTransactionWrapper, rhs: ZcashTransactionWrapper) -> Bool { + public static func < (lhs: ZcashTransactionWrapper, rhs: ZcashTransactionWrapper) -> Bool { if lhs.timestamp != rhs.timestamp { return lhs.timestamp > rhs.timestamp } else { @@ -47,24 +45,19 @@ extension ZcashTransactionWrapper: Comparable { } } - public static func ==(lhs: ZcashTransactionWrapper, rhs: ZcashTransactionWrapper) -> Bool { + public static func == (lhs: ZcashTransactionWrapper, rhs: ZcashTransactionWrapper) -> Bool { lhs.transactionHash == rhs.transactionHash } - } extension ZcashTransactionWrapper: Hashable { - public func hash(into hasher: inout Hasher) { hasher.combine(transactionHash) } - } extension ZcashTransactionWrapper { - var description: String { "TX(Zcash) === hash:\(transactionHash) : \(recipientAddress?.prefix(6) ?? "N/A") : \(transactionIndex) height: \(minedHeight?.description ?? "N/A") timestamp \(timestamp.description)" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressParserChain.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressParserChain.swift index c75bc49404..da75b35353 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressParserChain.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressParserChain.swift @@ -60,7 +60,7 @@ extension AddressParserChain { } return Single.zip(singles) { handlers in - return handlers.compactMap { $0 } + handlers.compactMap { $0 } } } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressService.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressService.swift index 9619a67a8d..45c6cf689b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressService.swift @@ -25,7 +25,7 @@ class AddressService { private let showContactsRelay = PublishRelay() var showContacts: Bool { - guard let contactBookManager, let blockchainType = blockchainType else { + guard let contactBookManager, let blockchainType else { return false } @@ -69,14 +69,14 @@ class AddressService { switch mode { case .blockchainType: - addressUriParser = AddressParserFactory.parser(blockchainType: blockchainType, tokenType: nil) //todo: Check if tokenType is nesessary + addressUriParser = AddressParserFactory.parser(blockchainType: blockchainType, tokenType: nil) // TODO: Check if tokenType is nesessary addressParserChain = blockchainType.flatMap { AddressParserFactory.parserChain(blockchainType: $0) } case let .parsers(uriParser, parserChain): addressUriParser = uriParser addressParserChain = parserChain } - if let initialAddress = initialAddress { + if let initialAddress { state = .success(initialAddress) } else { state = .empty @@ -91,7 +91,7 @@ class AddressService { private func register(customErrorService: IErrorService?) { customErrorDisposeBag = DisposeBag() - if let customErrorService = customErrorService { + if let customErrorService { subscribe(disposeBag, customErrorService.errorObservable) { [weak self] in self?.sync(customError: $0) } @@ -103,7 +103,7 @@ class AddressService { } private func sync(address: Address?) { - guard let address = address else { + guard let address else { state = .empty return } @@ -148,7 +148,7 @@ extension AddressService { return } - guard let addressParserChain = addressParserChain else { + guard let addressParserChain else { sync(address: Address(raw: text)) return } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressUriParser.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressUriParser.swift index ca9785de27..e7d20245e7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressUriParser.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressUriParser.swift @@ -18,7 +18,6 @@ class AddressUriParser { private func fullAddress(scheme: String, address: String, uriBlockchainUid: String? = nil) -> String { // there is no explicit indication of the blockchain in the uri. We use the rules of the blockchain parser guard let uriBlockchainUid else { - // if has blockchainType check if needed prefix if let blockchainType { return pair(blockchainType, address) @@ -60,13 +59,15 @@ class AddressUriParser { if let uid: String = uri.value(field: .blockchainUid), let blockchainType, - blockchainType != BlockchainType(uid: uid) { + blockchainType != BlockchainType(uid: uid) + { return .invalidBlockchainType } if let uid: String = uri.value(field: .tokenUid), let tokenType, - tokenType != TokenType(id: uid) { + tokenType != TokenType(id: uid) + { return .invalidTokenType } @@ -106,4 +107,4 @@ extension AddressUriParser { case noUri case uri(AddressUri) } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/BinanceAddressParserItem.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/BinanceAddressParserItem.swift index f2c61da87a..ec2356b462 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/BinanceAddressParserItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/BinanceAddressParserItem.swift @@ -1,8 +1,8 @@ -import Foundation -import RxSwift -import BitcoinCore import BinanceChainKit +import BitcoinCore +import Foundation import MarketKit +import RxSwift class BinanceAddressParserItem { private let parserType: ParserType @@ -14,10 +14,10 @@ class BinanceAddressParserItem { private func validate(address: String) -> Single
{ do { switch parserType { - case .adapter(let adapter): + case let .adapter(adapter): try adapter.validate(address: address) return Single.just(Address(raw: address, domain: nil)) - case .validator(let validator): + case let .validator(validator): try validator.validate(address: address) return Single.just(Address(raw: address, domain: nil)) } @@ -26,7 +26,6 @@ class BinanceAddressParserItem { return Single.error(error) } } - } extension BinanceAddressParserItem: IAddressParserItem { @@ -38,17 +37,14 @@ extension BinanceAddressParserItem: IAddressParserItem { func isValid(address: String) -> Single { validate(address: address) - .map { _ in true } - .catchErrorJustReturn(false) + .map { _ in true } + .catchErrorJustReturn(false) } - } extension BinanceAddressParserItem { - enum ParserType { case adapter(ISendBinanceAdapter) case validator(BinanceAddressValidator) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/DashAddressParserItem.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/DashAddressParserItem.swift index 0e08e48807..c3e5432ea7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/DashAddressParserItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/DashAddressParserItem.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import MarketKit +import RxSwift class DashAddressParserItem { private let adapter: ISendDashAdapter @@ -8,7 +8,6 @@ class DashAddressParserItem { init(adapter: ISendDashAdapter) { self.adapter = adapter } - } extension DashAddressParserItem: IAddressParserItem { @@ -31,5 +30,4 @@ extension DashAddressParserItem: IAddressParserItem { return Single.just(false) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/EnsAddressParserItem.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/EnsAddressParserItem.swift index 3c285163a7..a0d4adbb97 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/EnsAddressParserItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/EnsAddressParserItem.swift @@ -1,6 +1,6 @@ -import RxSwift -import MarketKit import EvmKit +import MarketKit +import RxSwift class EnsAddressParserItem { static let registrars = ["eth", "xyz", "luxe", "kred", "art"] @@ -19,12 +19,11 @@ class EnsAddressParserItem { private func rawAddressHandle(address: Address) -> Single
{ rawAddressParserItem - .handle(address: address.raw) - .map { rawAddress in - Address(raw: rawAddress.raw, domain: address.domain) - } + .handle(address: address.raw) + .map { rawAddress in + Address(raw: rawAddress.raw, domain: address.domain) + } } - } extension EnsAddressParserItem: IAddressParserItem { @@ -33,23 +32,22 @@ extension EnsAddressParserItem: IAddressParserItem { func handle(address: String) -> Single
{ let blockchainType = blockchainType return provider.address(domain: address) - .flatMap { [weak self] resolvedAddress in - let address = Address(raw: resolvedAddress.hex, domain: address) - return self?.rawAddressHandle(address: address) ?? Single.just(address) - }.catchError { _ in - .error(AddressService.AddressError.invalidAddress(blockchainName: blockchainType.uid)) - } + .flatMap { [weak self] resolvedAddress in + let address = Address(raw: resolvedAddress.hex, domain: address) + return self?.rawAddressHandle(address: address) ?? Single.just(address) + }.catchError { _ in + .error(AddressService.AddressError.invalidAddress(blockchainName: blockchainType.uid)) + } } func isValid(address: String) -> Single { let parts = address.components(separatedBy: ".") if parts.count > 1, - let last = parts.last?.lowercased() { - + let last = parts.last?.lowercased() + { return .just(Self.registrars.contains(last)) } return .just(false) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/EvmAddressParserItem.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/EvmAddressParserItem.swift index e734fd287e..29ffbb7042 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/EvmAddressParserItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/EvmAddressParserItem.swift @@ -1,6 +1,6 @@ -import RxSwift import EvmKit import MarketKit +import RxSwift class EvmAddressParser: IAddressParserItem { let blockchainType: BlockchainType @@ -22,5 +22,4 @@ class EvmAddressParser: IAddressParserItem { let address = try? EvmKit.Address(hex: address) return Single.just(address != nil) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/TronAddressParserItem.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/TronAddressParserItem.swift index 5c9eb117b3..713634c2f4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/TronAddressParserItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/TronAddressParserItem.swift @@ -1,6 +1,6 @@ +import MarketKit import RxSwift import TronKit -import MarketKit class TronAddressParser: IAddressParserItem { var blockchainType: BlockchainType { .tron } @@ -18,5 +18,4 @@ class TronAddressParser: IAddressParserItem { let address = try? TronKit.Address(address: address) return Single.just(address != nil) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/UdnAddressParserItem.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/UdnAddressParserItem.swift index aad87fa943..7fdc443ab6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/UdnAddressParserItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/UdnAddressParserItem.swift @@ -1,8 +1,7 @@ -import RxSwift import MarketKit +import RxSwift class UdnAddressParserItem { - private let provider = AddressResolutionProvider() private let coinCode: String private let platformCoinCode: String? @@ -27,8 +26,8 @@ class UdnAddressParserItem { return singles[index].flatMap { [weak self] resultOfAddress in switch resultOfAddress { - case .success(let address): - return Single.just(Result.success(address)) + case let .success(address): + return Single.just(Result.success(address)) case .failure: return self?.resolve(index: index + 1, singles: singles) ?? failure } @@ -37,12 +36,11 @@ class UdnAddressParserItem { private func rawAddressHandle(address: Address) -> Single
{ rawAddressParserItem - .handle(address: address.raw) - .map { rawAddress in - Address(raw: rawAddress.raw, domain: address.domain) - } + .handle(address: address.raw) + .map { rawAddress in + Address(raw: rawAddress.raw, domain: address.domain) + } } - } extension UdnAddressParserItem: IAddressParserItem { @@ -50,42 +48,40 @@ extension UdnAddressParserItem: IAddressParserItem { func handle(address: String) -> Single
{ var singles = [Single>]() - if let chain = chain { + if let chain { singles.append(provider.resolveSingle(domain: address, ticker: coinCode, chain: chain)) } singles.append(provider.resolveSingle(domain: address, ticker: coinCode, chain: nil)) - if let platformCoinCode = platformCoinCode { + if let platformCoinCode { singles.append(provider.resolveSingle(domain: address, ticker: platformCoinCode, chain: nil)) } return resolve(singles: singles) - .flatMap { [weak self] result in - switch result { - case .success(let resolvedAddress): - let address = Address(raw: resolvedAddress, domain: address) - return self?.rawAddressHandle(address: address) ?? Single.just(address) - case .failure(let error): - return Single.error(error) - } + .flatMap { [weak self] result in + switch result { + case let .success(resolvedAddress): + let address = Address(raw: resolvedAddress, domain: address) + return self?.rawAddressHandle(address: address) ?? Single.just(address) + case let .failure(error): + return Single.error(error) } + } } func isValid(address: String) -> Single { let parts = address.components(separatedBy: ".") if parts.count > 1, let last = parts.last?.lowercased(), - !exceptionRegistrars.contains(last) { - + !exceptionRegistrars.contains(last) + { return provider.isValid(domain: address) } return .just(false) } - } extension UdnAddressParserItem { - static func chainCoinCode(blockchainType: BlockchainType) -> String { switch blockchainType { case .bitcoin: return "BTC" @@ -106,7 +102,7 @@ extension UdnAddressParserItem { case .tron: return "TRX" case .solana: return "SOL" case .ton: return "TON" - case .unsupported(let uid): return uid + case let .unsupported(uid): return uid } } @@ -119,17 +115,15 @@ extension UdnAddressParserItem { default: return nil } } - } extension UdnAddressParserItem { - static func item(rawAddressParserItem: IAddressParserItem, coinCode: String, token: Token?) -> UdnAddressParserItem { let item = UdnAddressParserItem( - rawAddressParserItem: rawAddressParserItem, - coinCode: coinCode, - platformCoinCode: token.flatMap { chainCoinCode(blockchainType: $0.blockchainType) }, - chain: token.flatMap { chain(token: $0) } + rawAddressParserItem: rawAddressParserItem, + coinCode: coinCode, + platformCoinCode: token.flatMap { chainCoinCode(blockchainType: $0.blockchainType) }, + chain: token.flatMap { chain(token: $0) } ) item.exceptionRegistrars = EnsAddressParserItem.registrars @@ -138,14 +132,13 @@ extension UdnAddressParserItem { static func item(rawAddressParserItem: IAddressParserItem, blockchainType: BlockchainType) -> UdnAddressParserItem { let item = UdnAddressParserItem( - rawAddressParserItem: rawAddressParserItem, - coinCode: chainCoinCode(blockchainType: blockchainType), - platformCoinCode: nil, - chain: nil + rawAddressParserItem: rawAddressParserItem, + coinCode: chainCoinCode(blockchainType: blockchainType), + platformCoinCode: nil, + chain: nil ) item.exceptionRegistrars = EnsAddressParserItem.registrars return item } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/ZcashAddressParserItem.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/ZcashAddressParserItem.swift index 4614d277ac..bfca14b473 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/ZcashAddressParserItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/ZcashAddressParserItem.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import MarketKit +import RxSwift class ZcashAddressParserItem { private let parserType: ParserType @@ -12,10 +12,10 @@ class ZcashAddressParserItem { private func validate(address: String, checkSendToSelf: Bool) -> Single
{ do { switch parserType { - case .adapter(let adapter): + case let .adapter(adapter): _ = try adapter.validate(address: address, checkSendToSelf: checkSendToSelf) return Single.just(Address(raw: address, domain: nil)) - case .validator(let validator): + case let .validator(validator): try validator.validate(address: address) return Single.just(Address(raw: address, domain: nil)) } @@ -24,7 +24,6 @@ class ZcashAddressParserItem { return Single.error(error) } } - } extension ZcashAddressParserItem: IAddressParserItem { @@ -36,17 +35,14 @@ extension ZcashAddressParserItem: IAddressParserItem { func isValid(address: String) -> Single { validate(address: address, checkSendToSelf: false) - .map { _ in true } - .catchErrorJustReturn(false) + .map { _ in true } + .catchErrorJustReturn(false) } - } extension ZcashAddressParserItem { - enum ParserType { case adapter(ISendZcashAdapter) case validator(ZcashAddressValidator) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCrypto.swift b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCrypto.swift index 1f44204a09..bac0c90fac 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCrypto.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCrypto.swift @@ -59,21 +59,21 @@ extension BackupCrypto { // validation passphrase let isValid = try BackupCryptoHelper.isValid( - macHex: mac, - pass: passphrase, - message: cipherText.hs.data, - kdf: kdfParams + macHex: mac, + pass: passphrase, + message: cipherText.hs.data, + kdf: kdfParams ) guard isValid else { throw RestoreCloudModule.RestoreError.invalidPassword } return try BackupCryptoHelper.AES128( - operation: .decrypt, - ivHex: cipherParams.iv, - pass: passphrase, - message: data, - kdf: kdfParams + operation: .decrypt, + ivHex: cipherParams.iv, + pass: passphrase, + message: data, + kdf: kdfParams ) } } @@ -98,27 +98,27 @@ extension BackupCrypto { let iv = BackupCryptoHelper.generateInitialVector().hs.hex let cipherText = try BackupCryptoHelper.AES128( - operation: .encrypt, - ivHex: iv, - pass: passphrase, - message: data, - kdf: kdf + operation: .encrypt, + ivHex: iv, + pass: passphrase, + message: data, + kdf: kdf ) let encodedCipherText = cipherText.base64EncodedString() let mac = try BackupCryptoHelper.mac( - pass: passphrase, - message: encodedCipherText.hs.data, - kdf: kdf + pass: passphrase, + message: encodedCipherText.hs.data, + kdf: kdf ) return BackupCrypto( - cipher: BackupCryptoHelper.defaultCypher, - cipherParams: CipherParams(iv: iv), - cipherText: encodedCipherText, - kdf: BackupCryptoHelper.defaultKdf, - kdfParams: kdf, - mac: mac.hs.hex + cipher: BackupCryptoHelper.defaultCypher, + cipherParams: CipherParams(iv: iv), + cipherText: encodedCipherText, + kdf: BackupCryptoHelper.defaultKdf, + kdfParams: kdf, + mac: mac.hs.hex ) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCryptoHelper.swift b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCryptoHelper.swift index db030cc405..f4ce93a54f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCryptoHelper.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/BackupCryptoHelper.swift @@ -112,12 +112,12 @@ extension BackupCryptoHelper { public static func mac(pass: String, message: Data, kdf: KdfParams) throws -> Data { let key = try BackupCryptoHelper.makeScrypt( - pass: pass.hs.data, - salt: kdf.salt.hs.data, - dkLen: kdf.dklen, - N: kdf.n, - r: kdf.r, - p: kdf.p + pass: pass.hs.data, + salt: kdf.salt.hs.data, + dkLen: kdf.dklen, + N: kdf.n, + r: kdf.r, + p: kdf.p ) let startIndex = kdf.dklen / 2 let lastHalfKey = key.suffix(from: startIndex) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/CipherParams.swift b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/CipherParams.swift index 10a8b0719d..e163bc0ac1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/CipherParams.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/CipherParams.swift @@ -20,5 +20,4 @@ class CipherParams: Codable { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(iv, forKey: .iv) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/FullBackup.swift b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/FullBackup.swift index 5e23d8b583..98398c6bd8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/FullBackup.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/FullBackup.swift @@ -25,8 +25,8 @@ extension FullBackup: Codable { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(String.self, forKey: .id) do { - wallets = (try container.decode([FailableDecodable].self, forKey: .wallets)) - .compactMap { $0.base } + wallets = try (container.decode([FailableDecodable].self, forKey: .wallets)) + .compactMap(\.base) } catch { wallets = [] } @@ -49,8 +49,7 @@ extension FullBackup: Codable { } } -struct FailableDecodable : Decodable { - +struct FailableDecodable: Decodable { let base: Base? init(from decoder: Decoder) throws { diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/KdfParams.swift b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/KdfParams.swift index 5d6f11a2e8..1a66e0258b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/KdfParams.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/KdfParams.swift @@ -42,5 +42,4 @@ class KdfParams: Codable { self.r = r self.salt = salt } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/SettingsBackup.swift b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/SettingsBackup.swift index 4f1b33bb07..931a5aa82b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Crypto/SettingsBackup.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Crypto/SettingsBackup.swift @@ -1,5 +1,5 @@ -import Foundation import Chart +import Foundation import ThemeKit struct SettingsBackup: Codable { @@ -40,7 +40,6 @@ struct SettingsBackup: Codable { case balanceAutoHide = "balance_auto_hide" case appIcon = "app_icon" } - } extension SettingsBackup { diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/CoinService.swift b/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/CoinService.swift index 20597c6f7b..23dae1c9db 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/CoinService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/CoinService.swift @@ -1,7 +1,7 @@ -import Foundation import BigInt -import MarketKit +import Foundation import HsExtensions +import MarketKit protocol ICoinService { var rate: CurrencyValue? { get } @@ -23,11 +23,9 @@ class CoinService { self.currencyManager = currencyManager self.marketKit = marketKit } - } extension CoinService: ICoinService { - var rate: CurrencyValue? { let baseCurrency = currencyManager.baseCurrency @@ -57,15 +55,14 @@ extension CoinService: ICoinService { func amountData(value: Decimal, sign: FloatingPointSign) -> AmountData { AmountData( - coinValue: CoinValue(kind: .token(token: token), value: Decimal(sign: sign, exponent: value.exponent, significand: value.significand)), - currencyValue: rate.map { - CurrencyValue(currency: $0.currency, value: $0.value * value) - } + coinValue: CoinValue(kind: .token(token: token), value: Decimal(sign: sign, exponent: value.exponent, significand: value.significand)), + currencyValue: rate.map { + CurrencyValue(currency: $0.currency, value: $0.value * value) + } ) } func amountData(value: BigUInt, sign: FloatingPointSign = .plus) -> AmountData { amountData(value: Decimal(bigUInt: value, decimals: token.decimals) ?? 0, sign: sign) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/EvmCoinServiceFactory.swift b/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/EvmCoinServiceFactory.swift index 3ed82d8a49..38091a3d68 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/EvmCoinServiceFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Ethereum/EvmCoinServiceFactory.swift @@ -1,6 +1,6 @@ import BigInt -import MarketKit import EvmKit +import MarketKit import TronKit class EvmCoinServiceFactory { @@ -49,5 +49,4 @@ class EvmCoinServiceFactory { func coinService(token: Token) -> CoinService { CoinService(token: token, currencyManager: currencyManager, marketKit: marketKit) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Factories/AccountFactory.swift b/UnstoppableWallet/UnstoppableWallet/Core/Factories/AccountFactory.swift index abc36cba0a..d548f99d40 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Factories/AccountFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Factories/AccountFactory.swift @@ -30,7 +30,7 @@ extension AccountFactory { } var nextWatchAccountName: String { - let watchAccounts = accountManager.accounts.filter { $0.watchAccount } + let watchAccounts = accountManager.accounts.filter(\.watchAccount) let order = watchAccounts.count + 1 return "Watch Wallet \(order)" diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressParserFactory.swift b/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressParserFactory.swift index f95c537980..02ca5a79ed 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressParserFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressParserFactory.swift @@ -10,15 +10,15 @@ import ZcashLightClientKit class AddressParserFactory { static let uriBlockchainTypes: [BlockchainType] = [ - .bitcoin, - .bitcoinCash, - .ecash, - .litecoin, - .dash, - .zcash, - .ethereum, - .binanceChain, - .tron, + .bitcoin, + .bitcoinCash, + .ecash, + .litecoin, + .dash, + .zcash, + .ethereum, + .binanceChain, + .tron, ] static func parser(blockchainType: BlockchainType?, tokenType: TokenType?) -> AddressUriParser { @@ -88,7 +88,8 @@ class AddressParserFactory { handlers.append(udnAddressParserItem) if let httpSyncSource = App.shared.evmSyncSourceManager.httpSyncSource(blockchainType: .ethereum), - let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) { + let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) + { handlers.append(ensAddressParserItem) } } @@ -166,4 +167,4 @@ extension BlockchainType { default: return false } } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Factories/EvmAccountManagerFactory.swift b/UnstoppableWallet/UnstoppableWallet/Core/Factories/EvmAccountManagerFactory.swift index d8708162e5..316704c6b6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Factories/EvmAccountManagerFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Factories/EvmAccountManagerFactory.swift @@ -13,20 +13,17 @@ class EvmAccountManagerFactory { self.evmAccountRestoreStateManager = evmAccountRestoreStateManager self.marketKit = marketKit } - } extension EvmAccountManagerFactory { - func evmAccountManager(blockchainType: BlockchainType, evmKitManager: EvmKitManager) -> EvmAccountManager { EvmAccountManager( - blockchainType: blockchainType, - accountManager: accountManager, - walletManager: walletManager, - marketKit: marketKit, - evmKitManager: evmKitManager, - evmAccountRestoreStateManager: evmAccountRestoreStateManager + blockchainType: blockchainType, + accountManager: accountManager, + walletManager: walletManager, + marketKit: marketKit, + evmKitManager: evmKitManager, + evmAccountRestoreStateManager: evmAccountRestoreStateManager ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Factories/FeeRateProviderFactory.swift b/UnstoppableWallet/UnstoppableWallet/Core/Factories/FeeRateProviderFactory.swift index 1b802e4d63..403bbcce45 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Factories/FeeRateProviderFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Factories/FeeRateProviderFactory.swift @@ -13,5 +13,4 @@ class FeeRateProviderFactory { default: return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Factories/PredefinedBlockchainService.swift b/UnstoppableWallet/UnstoppableWallet/Core/Factories/PredefinedBlockchainService.swift index bfb2b7caac..b3b4393fc8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Factories/PredefinedBlockchainService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Factories/PredefinedBlockchainService.swift @@ -6,11 +6,9 @@ class PredefinedBlockchainService { init(restoreSettingsManager: RestoreSettingsManager) { self.restoreSettingsManager = restoreSettingsManager } - } extension PredefinedBlockchainService { - func prepareNew(account: Account, blockchainType: BlockchainType) { var restoreSettings: RestoreSettings = [:] @@ -26,5 +24,4 @@ extension PredefinedBlockchainService { restoreSettingsManager.save(settings: restoreSettings, account: account, blockchainType: blockchainType) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/FaqUrlHelper.swift b/UnstoppableWallet/UnstoppableWallet/Core/FaqUrlHelper.swift index 38db8ea2b6..f76d286d07 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/FaqUrlHelper.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/FaqUrlHelper.swift @@ -1,7 +1,6 @@ import Foundation class FaqUrlHelper { - static var privateKeysUrl: URL? { URL(string: "faq/en/management/what-are-private-keys-mnemonic-phrase-wallet-seed.md", relativeTo: AppConfig.faqIndexUrl) } @@ -9,5 +8,4 @@ class FaqUrlHelper { static var walletConnectUrl: URL? { URL(string: "faq/en/defi/defi-risks.md", relativeTo: AppConfig.faqIndexUrl) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Fiat/AmountTypeSwitchService.swift b/UnstoppableWallet/UnstoppableWallet/Core/Fiat/AmountTypeSwitchService.swift index 6cc2f9e57b..57a93bcd77 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Fiat/AmountTypeSwitchService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Fiat/AmountTypeSwitchService.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift class AmountTypeSwitchService { private let amountTypeKey = "amount-type-switch-service-amount-type" @@ -40,29 +40,28 @@ class AmountTypeSwitchService { disposeBag = DisposeBag() Observable.combineLatest(toggleAvailableObservables) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] array in - self?.syncToggleAvailable(array: array) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] array in + self?.syncToggleAvailable(array: array) + }) + .disposed(by: disposeBag) } private func syncToggleAvailable(array: [Bool]) { toggleAvailable = array.allSatisfy { $0 } - if !toggleAvailable && amountType == .currency { // reset input type if it was set to currency + if !toggleAvailable, amountType == .currency { // reset input type if it was set to currency amountType = .coin } else if toggleAvailable, useLocalStorage, let savedAmountType = userDefaultsStorage.value(for: amountTypeKey).flatMap({ AmountType(rawValue: $0) }), - savedAmountType == .currency && amountType == .coin { + savedAmountType == .currency, amountType == .coin + { amountType = .currency } } - } extension AmountTypeSwitchService { - func toggle() { if toggleAvailable { amountType = !amountType @@ -84,11 +83,9 @@ extension AmountTypeSwitchService { toggleAvailableObservables.append(toggleAllowedObservable) subscribeToObservables() } - } extension AmountTypeSwitchService { - enum AmountType: String { case coin case currency @@ -96,7 +93,5 @@ extension AmountTypeSwitchService { static prefix func ! (lhs: Self) -> Self { lhs == .coin ? currency : coin } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Fiat/FiatService.swift b/UnstoppableWallet/UnstoppableWallet/Core/Fiat/FiatService.swift index 773ead2fdf..43a59db0f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Fiat/FiatService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Fiat/FiatService.swift @@ -1,8 +1,8 @@ -import Foundation import Combine -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class FiatService { private var disposeBag = DisposeBag() @@ -41,7 +41,7 @@ class FiatService { } } - private let amountAlreadyUpdatedRelay = PublishRelay<()>() + private let amountAlreadyUpdatedRelay = PublishRelay() private var toggleAvailableRelay = BehaviorRelay(value: false) @@ -63,7 +63,7 @@ class FiatService { } private func sync(coinPrice: CoinPrice?) { - if let coinPrice = coinPrice, !coinPrice.expired { + if let coinPrice, !coinPrice.expired { price = coinPrice.value if coinAmountLocked { @@ -79,7 +79,7 @@ class FiatService { sync() } - private func sync(amountType: AmountTypeSwitchService.AmountType) { + private func sync(amountType _: AmountTypeSwitchService.AmountType) { sync() } @@ -105,7 +105,7 @@ class FiatService { } private func syncCoinAmount() { - if let currencyAmount = currencyAmount, let price = price { + if let currencyAmount, let price { coinAmount = price == 0 ? 0 : currencyAmount / price } else { coinAmount = 0 @@ -115,7 +115,7 @@ class FiatService { } private func syncCurrencyAmount() { - if let price = price { + if let price { currencyAmount = coinAmount * price } else { currencyAmount = nil @@ -133,11 +133,9 @@ class FiatService { .store(in: &cancellables) } } - } extension FiatService { - var coinAmountObservable: Observable { coinAmountRelay.asObservable() } @@ -150,7 +148,7 @@ extension FiatService { secondaryAmountInfoRelay.asObservable() } - var amountAlreadyUpdatedObservable: Observable<()> { + var amountAlreadyUpdatedObservable: Observable { amountAlreadyUpdatedRelay.asObservable() } @@ -166,21 +164,20 @@ extension FiatService { self.coinValueKind = coinValueKind cancellables = Set() - var fetching: Bool = true + var fetching = true - if let coinValueKind = coinValueKind { + if let coinValueKind { switch coinValueKind { - case .token(let token): + case let .token(token): fetchRate(coin: token.coin, subscribe: !token.isCustom) - case .coin(let coin, _): + case let .coin(coin, _): fetchRate(coin: coin, subscribe: false) - case .cexAsset(let cexAsset): + case let .cexAsset(cexAsset): if let coin = cexAsset.coin { fetchRate(coin: coin, subscribe: false) } else { fetching = false } - } } else { fetching = false @@ -222,14 +219,11 @@ extension FiatService { syncCurrencyAmount() sync() } - } extension FiatService { - enum PrimaryInfo { case amountInfo(amountInfo: AmountInfo?) case amount(amount: Decimal) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Global.swift b/UnstoppableWallet/UnstoppableWallet/Core/Global.swift index d515d9fed4..f29334d6fa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Global.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Global.swift @@ -1,7 +1,7 @@ +import Combine import Foundation -import RxSwift import RxCocoa -import Combine +import RxSwift func subscribe(_ disposeBag: DisposeBag, _ driver: Driver, _ onNext: ((T) -> Void)? = nil) { driver.drive(onNext: onNext).disposed(by: disposeBag) @@ -13,23 +13,23 @@ func subscribe(_ disposeBag: DisposeBag, _ signal: Signal, _ onNext: ((T) func subscribe(_ disposeBag: DisposeBag, _ observable: Observable?, _ onNext: ((T) -> Void)? = nil) { observable? - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: onNext) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: onNext) + .disposed(by: disposeBag) } func subscribeSerial(_ disposeBag: DisposeBag, _ observable: Observable, _ onNext: ((T) -> Void)? = nil) { observable - .subscribe(onNext: onNext) - .disposed(by: disposeBag) + .subscribe(onNext: onNext) + .disposed(by: disposeBag) } func subscribe(_ scheduler: ImmediateSchedulerType, _ disposeBag: DisposeBag, _ observable: Observable, _ onNext: ((T) -> Void)? = nil) { observable - .observeOn(scheduler) - .subscribe(onNext: onNext) - .disposed(by: disposeBag) + .observeOn(scheduler) + .subscribe(onNext: onNext) + .disposed(by: disposeBag) } func subscribe(_ cancellables: inout Set, _ publisher: AnyPublisher, _ receiveValue: @escaping ((T) -> Void)) { diff --git a/UnstoppableWallet/UnstoppableWallet/Core/HdWalletExtensions.swift b/UnstoppableWallet/UnstoppableWallet/Core/HdWalletExtensions.swift index 2631152343..5eee9d6e75 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/HdWalletExtensions.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/HdWalletExtensions.swift @@ -1,7 +1,6 @@ import HdWalletKit extension Mnemonic.Language { - var language: String { switch self { case .english: return "en" @@ -16,5 +15,4 @@ extension Mnemonic.Language { case .portuguese: return "pt" } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountManager.swift index 77de29848f..824c267ddb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountManager.swift @@ -64,7 +64,6 @@ class AccountManager { accountsLostRelay.accept(true) } } - } extension AccountManager { diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountRestoreWarningManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountRestoreWarningManager.swift index c203f2912a..0b7c0889d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountRestoreWarningManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AccountRestoreWarningManager.swift @@ -9,25 +9,23 @@ class AccountRestoreWarningManager { self.accountManager = accountManager self.userDefaultsStorage = userDefaultsStorage } - } extension AccountRestoreWarningManager { - var hasNonStandard: Bool { - !accountManager.accounts.filter { $0.nonStandard }.isEmpty + !accountManager.accounts.filter(\.nonStandard).isEmpty } var hasNonStandardObservable: Observable { - accountManager.accountsObservable.map { !$0.filter { $0.nonStandard }.isEmpty } + accountManager.accountsObservable.map { !$0.filter(\.nonStandard).isEmpty } } var hasNonRecommended: Bool { - !accountManager.accounts.filter { $0.nonRecommended }.isEmpty + !accountManager.accounts.filter(\.nonRecommended).isEmpty } var hasNonRecommendedObservable: Observable { - accountManager.accountsObservable.map { !$0.filter { $0.nonStandard }.isEmpty } + accountManager.accountsObservable.map { !$0.filter(\.nonStandard).isEmpty } } func removeIgnoreWarning(account: Account) { @@ -37,7 +35,6 @@ extension AccountRestoreWarningManager { func setIgnoreWarning(account: Account) { userDefaultsStorage.set(value: true, for: AccountRestoreWarningFactory.keyAccountWarningPrefix + account.id) } - } class AccountRestoreWarningFactory { @@ -58,7 +55,7 @@ class AccountRestoreWarningFactory { return nil } - return CancellableTitledCaution(title: "note".localized, text: "restore.warning.non_recommended.description".localized, type: .warning, cancellable: canIgnoreActiveAccountWarning) + return CancellableTitledCaution(title: "note".localized, text: "restore.warning.non_recommended.description".localized, type: .warning, cancellable: canIgnoreActiveAccountWarning) } return nil } @@ -75,5 +72,4 @@ class AccountRestoreWarningFactory { return URL(string: fileUrl, relativeTo: faqIndexUrl) } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AdapterManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AdapterManager.swift index 424d76b6f8..4ebdce7997 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AdapterManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AdapterManager.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class AdapterManager { private let disposeBag = DisposeBag() @@ -18,18 +18,19 @@ class AdapterManager { private var _adapterData = AdapterData(adapterMap: [:], account: nil) init(adapterFactory: AdapterFactory, walletManager: WalletManager, evmBlockchainManager: EvmBlockchainManager, - tronKitManager: TronKitManager, btcBlockchainManager: BtcBlockchainManager) { + tronKitManager: TronKitManager, btcBlockchainManager: BtcBlockchainManager) + { self.adapterFactory = adapterFactory self.walletManager = walletManager self.evmBlockchainManager = evmBlockchainManager self.tronKitManager = tronKitManager walletManager.activeWalletDataUpdatedObservable - .observeOn(SerialDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] walletData in - self?.initAdapters(wallets: walletData.wallets, account: walletData.account) - }) - .disposed(by: disposeBag) + .observeOn(SerialDispatchQueueScheduler(qos: .utility)) + .subscribe(onNext: { [weak self] walletData in + self?.initAdapters(wallets: walletData.wallets, account: walletData.account) + }) + .disposed(by: disposeBag) for blockchain in evmBlockchainManager.allBlockchains { subscribe(disposeBag, evmBlockchainManager.evmKitManager(blockchainType: blockchain.type).evmKitUpdatedObservable) { [weak self] in self?.handleUpdatedEvmKit(blockchain: blockchain) } @@ -107,11 +108,9 @@ class AdapterManager { let activeWalletData = walletManager.activeWalletData initAdapters(wallets: activeWalletData.wallets, account: activeWalletData.account) } - } extension AdapterManager { - var adapterData: AdapterData { queue.sync { _adapterData } } @@ -126,7 +125,7 @@ extension AdapterManager { func adapter(for token: Token) -> IAdapter? { queue.sync { - guard let wallet = walletManager.activeWallets.first(where: { $0.token == token } ) else { + guard let wallet = walletManager.activeWallets.first(where: { $0.token == token }) else { return nil } @@ -176,14 +175,11 @@ extension AdapterManager { } } } - } extension AdapterManager { - struct AdapterData { var adapterMap: [Wallet: IAdapter] let account: Account? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AppIconManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AppIconManager.swift index d6f3cc3f57..dbf9b58bf2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/AppIconManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/AppIconManager.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift import UIKit class AppIconManager { @@ -12,7 +12,7 @@ class AppIconManager { .alternate(name: "AppIconYak", title: "Yak"), .alternate(name: "AppIconPunk", title: "Punk"), .alternate(name: "AppIcon1874", title: "#1874"), - .alternate(name: "AppIcon8ball", title: "8ball") + .alternate(name: "AppIcon8ball", title: "8ball"), ] private let appIconRelay = PublishRelay() @@ -26,11 +26,9 @@ class AppIconManager { init() { appIcon = Self.currentAppIcon } - } extension AppIconManager { - var appIconObservable: Observable { appIconRelay.asObservable() } @@ -42,5 +40,4 @@ extension AppIconManager { return .main } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BackupManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BackupManager.swift index 4010a6f53a..d6f1b7c912 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BackupManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BackupManager.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay import Combine import HsExtensions +import RxRelay +import RxSwift class BackupManager { private let accountManager: AccountManager @@ -18,13 +18,11 @@ class BackupManager { private func updateAllBackedUp() { allBackedUpRelay.accept(allBackedUp) } - } extension BackupManager { - var allBackedUp: Bool { - accountManager.accounts.allSatisfy { $0.backedUp } + accountManager.accounts.allSatisfy(\.backedUp) } var allBackedUpObservable: Observable { @@ -39,5 +37,4 @@ extension BackupManager { account.backedUp = true accountManager.update(account: account) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceConversionManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceConversionManager.swift index a085fb8811..de93dfb898 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceConversionManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceConversionManager.swift @@ -39,7 +39,7 @@ class BalanceConversionManager { let blockchainUid: String? = userDefaultsStorage.value(for: keyBlockchainUid) let blockchainType = blockchainUid.map { BlockchainType(uid: $0) } - if let blockchainType = blockchainType, let token = conversionTokens.first(where: { $0.blockchainType == blockchainType }) { + if let blockchainType, let token = conversionTokens.first(where: { $0.blockchainType == blockchainType }) { conversionToken = token } else { conversionToken = conversionTokens.first @@ -53,7 +53,7 @@ extension BalanceConversionManager { } func toggleConversionToken() { - guard conversionTokens.count > 1, let conversionToken = conversionToken else { + guard conversionTokens.count > 1, let conversionToken else { return } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceHiddenManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceHiddenManager.swift index e97f35894a..cd6142ed3e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceHiddenManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalanceHiddenManager.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift class BalanceHiddenManager { static let placeholder = "*****" @@ -23,7 +23,7 @@ class BalanceHiddenManager { if let balanceHidden: Bool = userDefaultsStorage.value(for: keyBalanceHidden) { self.balanceHidden = balanceHidden } else if let balanceHidden: Bool = userDefaultsStorage.value(for: "balance_hidden") { - // todo: temp solution for restoring from version 0.22 + // TODO: temp solution for restoring from version 0.22 self.balanceHidden = balanceHidden } else { balanceHidden = false @@ -40,11 +40,9 @@ class BalanceHiddenManager { self.balanceHidden = balanceHidden userDefaultsStorage.set(value: balanceHidden, for: keyBalanceHidden) } - } extension BalanceHiddenManager { - var balanceHiddenObservable: Observable { balanceHiddenRelay.asObservable() } @@ -67,5 +65,4 @@ extension BalanceHiddenManager { set(balanceHidden: true) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalancePrimaryValueManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalancePrimaryValueManager.swift index 4c6c04c579..b34176f905 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalancePrimaryValueManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BalancePrimaryValueManager.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift class BalancePrimaryValueManager { private let keyBalancePrimaryValue = "balance-primary-value" @@ -23,13 +23,10 @@ class BalancePrimaryValueManager { balancePrimaryValue = .coin } } - } extension BalancePrimaryValueManager { - var balancePrimaryValueObservable: Observable { balancePrimaryValueRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BinanceKitManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BinanceKitManager.swift index de907a7683..a47e25b53b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BinanceKitManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BinanceKitManager.swift @@ -1,6 +1,6 @@ +import BinanceChainKit import Foundation import RxSwift -import BinanceChainKit class BinanceKitManager { private weak var _binanceKit: BinanceChainKit? @@ -9,7 +9,7 @@ class BinanceKitManager { private let queue = DispatchQueue(label: "\(AppConfig.label).ethereum-kit-manager", qos: .userInitiated) private func _binanceKit(account: Account) throws -> BinanceChainKit { - if let _binanceKit = _binanceKit, let currentAccount = currentAccount, currentAccount == account { + if let _binanceKit, let currentAccount, currentAccount == account { return _binanceKit } @@ -18,10 +18,10 @@ class BinanceKitManager { } let binanceKit = try BinanceChainKit.instance( - seed: seed, - networkType: .mainNet, - walletId: account.id, - minLogLevel: .error + seed: seed, + networkType: .mainNet, + walletId: account.id, + minLogLevel: .error ) binanceKit.refresh() @@ -34,13 +34,11 @@ class BinanceKitManager { } extension BinanceKitManager { - var binanceKit: BinanceChainKit? { queue.sync { _binanceKit } } func binanceKit(account: Account) throws -> BinanceChainKit { - try queue.sync { try _binanceKit(account: account) } + try queue.sync { try _binanceKit(account: account) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BtcBlockchainManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BtcBlockchainManager.swift index cc827a48d8..ba5bc83667 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/BtcBlockchainManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/BtcBlockchainManager.swift @@ -9,7 +9,7 @@ class BtcBlockchainManager { .bitcoinCash, .ecash, .litecoin, - .dash + .dash, ] private let marketKit: MarketKit.Kit @@ -25,7 +25,7 @@ class BtcBlockchainManager { self.storage = storage do { - allBlockchains = try marketKit.blockchains(uids: blockchainTypes.map { $0.uid }) + allBlockchains = try marketKit.blockchains(uids: blockchainTypes.map(\.uid)) } catch { allBlockchains = [] } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/CoinManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/CoinManager.swift index b9fd906834..2268fb9100 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/CoinManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/CoinManager.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class CoinManager { private let marketKit: Kit @@ -14,13 +14,10 @@ class CoinManager { private func customToken(query: TokenQuery) -> Token? { walletManager.activeWallets.first(where: { $0.token.blockchainType == query.blockchainType && $0.token.type == query.tokenType })?.token } - } extension CoinManager { - func token(query: TokenQuery) throws -> Token? { try marketKit.token(query: query) ?? customToken(query: query) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/DebugLogger.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/DebugLogger.swift index 84761d3438..d4aa940e01 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/DebugLogger.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/DebugLogger.swift @@ -20,11 +20,9 @@ class DebugLogger { self.localStorage.debugLog = fullLog.joined(separator: "|") } } - } extension DebugLogger { - var logs: [String] { let fullLog = localStorage.debugLog ?? "" @@ -56,5 +54,4 @@ extension DebugLogger { func clearLogs() { localStorage.debugLog = nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/DeepLinkManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/DeepLinkManager.swift index d89422013c..a412541e59 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/DeepLinkManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/DeepLinkManager.swift @@ -28,7 +28,7 @@ extension DeepLinkManager { return true } - if scheme == "unstoppable.money" && host == "coin" { + if scheme == "unstoppable.money", host == "coin" { let uid = path.replacingOccurrences(of: "/", with: "") newSchemeRelay.accept(.coin(uid: uid)) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountManager.swift index ac80611229..82dd4be053 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountManager.swift @@ -132,7 +132,7 @@ class EvmAccountManager { } } - handle(foundTokens: Array(foundTokens), suspiciousTokenTypes: Array(suspiciousTokenTypes.subtracting(foundTokens.map { $0.tokenType })), account: account, evmKit: evmKitWrapper.evmKit) + handle(foundTokens: Array(foundTokens), suspiciousTokenTypes: Array(suspiciousTokenTypes.subtracting(foundTokens.map(\.tokenType))), account: account, evmKit: evmKitWrapper.evmKit) } private func handle(foundTokens: [FoundToken], suspiciousTokenTypes: [TokenType], account: Account, evmKit: EvmKit.Kit) { @@ -144,7 +144,7 @@ class EvmAccountManager { // print("SUSPICIOUS TOKEN TYPES: \(suspiciousTokenTypes.count): \n\(suspiciousTokenTypes.map { $0.id }.joined(separator: "\n"))") do { - let queries = (foundTokens.map { $0.tokenType } + suspiciousTokenTypes).map { TokenQuery(blockchainType: blockchainType, tokenType: $0) } + let queries = (foundTokens.map(\.tokenType) + suspiciousTokenTypes).map { TokenQuery(blockchainType: blockchainType, tokenType: $0) } let tokens = try queries.chunks(500).map { try marketKit.tokens(queries: $0) }.flatMap { $0 } var tokenInfos = [TokenInfo]() @@ -194,7 +194,7 @@ class EvmAccountManager { // print("Handle Tokens: \(tokenInfos.count)\n\(tokenInfos.map { $0.type.id }.joined(separator: " "))") let existingWallets = walletManager.activeWallets - let existingTokenTypeIds = existingWallets.map { $0.token.type.id } + let existingTokenTypeIds = existingWallets.map(\.token.type.id) let newTokenInfos = tokenInfos.filter { !existingTokenTypeIds.contains($0.type.id) } // print("New Tokens: \(newTokenInfos.count)") @@ -217,7 +217,7 @@ class EvmAccountManager { } group.addTask { - let balance = (try? await dataProvider.fetchBalance(contractAddress: contractAddress, address: userAddress)) ?? 0 + let balance = await (try? dataProvider.fetchBalance(contractAddress: contractAddress, address: userAddress)) ?? 0 return (tokenInfo, balance) } } @@ -230,7 +230,7 @@ class EvmAccountManager { return results } - let nonZeroBalanceTokens = tokenInfos.filter { $0.balance > 0 }.map { $0.tokenInfo } + let nonZeroBalanceTokens = tokenInfos.filter { $0.balance > 0 }.map(\.tokenInfo) self?.handle(processedTokenInfos: nonZeroBalanceTokens, account: account) } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountRestoreStateManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountRestoreStateManager.swift index 57d7caa8fe..006d616ab9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountRestoreStateManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmAccountRestoreStateManager.swift @@ -9,7 +9,6 @@ class EvmAccountRestoreStateManager { } extension EvmAccountRestoreStateManager { - func isRestored(account: Account, blockchainType: BlockchainType) -> Bool { let state = try? storage.evmAccountRestoreState(accountId: account.id, blockchainUid: blockchainType.uid) return state?.restored ?? false @@ -19,5 +18,4 @@ extension EvmAccountRestoreStateManager { let state = EvmAccountRestoreState(accountId: account.id, blockchainUid: blockchainType.uid, restored: true) try? storage.save(evmAccountRestoreState: state) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmBlockchainManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmBlockchainManager.swift index 010a5bb92f..29ccb65376 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmBlockchainManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmBlockchainManager.swift @@ -1,6 +1,6 @@ import EvmKit -import MarketKit import HsToolKit +import MarketKit class EvmBlockchainManager { static let blockchainTypes: [BlockchainType] = [ @@ -24,7 +24,7 @@ class EvmBlockchainManager { var allBlockchains: [Blockchain] { do { - return try marketKit.blockchains(uids: EvmBlockchainManager.blockchainTypes.map { $0.uid }) + return try marketKit.blockchains(uids: EvmBlockchainManager.blockchainTypes.map(\.uid)) } catch { return [] } @@ -50,11 +50,9 @@ class EvmBlockchainManager { return (evmKitManager, evmAccountManager) } - } extension EvmBlockchainManager { - func blockchain(chainId: Int) -> Blockchain? { allBlockchains.first(where: { chain(blockchainType: $0.type).id == chainId }) } @@ -76,10 +74,10 @@ extension EvmBlockchainManager { case .ethereum: if testNetManager.testNetEnabled { return Chain( - id: 11155111, - coinType: 1, - syncInterval: 15, - isEIP1559Supported: true + id: 11_155_111, + coinType: 1, + syncInterval: 15, + isEIP1559Supported: true ) } else { return .ethereum @@ -87,10 +85,10 @@ extension EvmBlockchainManager { case .binanceSmartChain: if testNetManager.testNetEnabled { return Chain( - id: 97, - coinType: 1, - syncInterval: 15, - isEIP1559Supported: false + id: 97, + coinType: 1, + syncInterval: 15, + isEIP1559Supported: false ) } else { return .binanceSmartChain @@ -117,5 +115,4 @@ extension EvmBlockchainManager { func evmAccountManager(blockchainType: BlockchainType) -> EvmAccountManager { evmManagers(blockchainType: blockchainType).1 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmKitManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmKitManager.swift index 0b47bdb3d0..7ae4e7583c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmKitManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmKitManager.swift @@ -1,13 +1,13 @@ -import Foundation -import RxSwift -import RxRelay -import EvmKit import Eip20Kit -import NftKit -import UniswapKit -import OneInchKit +import EvmKit +import Foundation import HdWalletKit import MarketKit +import NftKit +import OneInchKit +import RxRelay +import RxSwift +import UniswapKit class EvmKitManager { let chain: Chain @@ -33,7 +33,7 @@ class EvmKitManager { private func handleUpdatedSyncSource(blockchainType: BlockchainType) { queue.sync { - guard let _evmKitWrapper = _evmKitWrapper else { + guard let _evmKitWrapper else { return } @@ -47,7 +47,7 @@ class EvmKitManager { } private func _evmKitWrapper(account: Account, blockchainType: BlockchainType) throws -> EvmKitWrapper { - if let _evmKitWrapper = _evmKitWrapper, let currentAccount = currentAccount, currentAccount == account { + if let _evmKitWrapper, let currentAccount, currentAccount == account { return _evmKitWrapper } @@ -73,12 +73,12 @@ class EvmKitManager { } let evmKit = try EvmKit.Kit.instance( - address: address, - chain: chain, - rpcSource: syncSource.rpcSource, - transactionSource: syncSource.transactionSource, - walletId: account.id, - minLogLevel: .error + address: address, + chain: chain, + rpcSource: syncSource.rpcSource, + transactionSource: syncSource.transactionSource, + walletId: account.id, + minLogLevel: .error ) Eip20Kit.Kit.addDecorators(to: evmKit) @@ -119,11 +119,9 @@ class EvmKitManager { return wrapper } - } extension EvmKitManager { - var evmKitCreatedObservable: Observable { evmKitCreatedRelay.asObservable() } @@ -143,7 +141,6 @@ extension EvmKitManager { try _evmKitWrapper(account: account, blockchainType: blockchainType) } } - } class EvmKitWrapper { @@ -160,39 +157,34 @@ class EvmKitWrapper { } func sendSingle(transactionData: TransactionData, gasPrice: GasPrice, gasLimit: Int, nonce: Int? = nil) -> Single { - guard let signer = signer else { + guard let signer else { return Single.error(SignerError.signerNotSupported) } return evmKit.rawTransaction(transactionData: transactionData, gasPrice: gasPrice, gasLimit: gasLimit, nonce: nonce) - .flatMap { [weak self] rawTransaction in - guard let strongSelf = self else { - return Single.error(AppError.weakReference) - } - - do { - let signature = try signer.signature(rawTransaction: rawTransaction) - return strongSelf.evmKit.sendSingle(rawTransaction: rawTransaction, signature: signature) - } catch { - return Single.error(error) - } + .flatMap { [weak self] rawTransaction in + guard let strongSelf = self else { + return Single.error(AppError.weakReference) } - } + do { + let signature = try signer.signature(rawTransaction: rawTransaction) + return strongSelf.evmKit.sendSingle(rawTransaction: rawTransaction, signature: signature) + } catch { + return Single.error(error) + } + } + } } extension EvmKitManager { - enum KitWrapperError: Error { case mnemonicNoSeed } - } extension EvmKitWrapper { - enum SignerError: Error { case signerNotSupported } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmLabelManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmLabelManager.swift index 9af3db6ba3..0ad885ebb0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmLabelManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/EvmLabelManager.swift @@ -1,6 +1,6 @@ +import EvmKit import Foundation import RxSwift -import EvmKit class EvmLabelManager { private let keyMethodLabelsTimestamp = "evm-label-manager-method-labels-timestamp" @@ -23,14 +23,14 @@ class EvmLabelManager { } provider.evmMethodLabelsSingle() - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onSuccess: { [weak self] labels in - try? self?.storage.save(evmMethodLabels: labels) - self?.saveMethodLabels(timestamp: timestamp) - }, onError: { error in - print("Method Labels sync error: \(error)") - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onSuccess: { [weak self] labels in + try? self?.storage.save(evmMethodLabels: labels) + self?.saveMethodLabels(timestamp: timestamp) + }, onError: { error in + print("Method Labels sync error: \(error)") + }) + .disposed(by: disposeBag) } private func syncAddressLabels(timestamp: Int) { @@ -39,14 +39,14 @@ class EvmLabelManager { } provider.evmAddressLabelsSingle() - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onSuccess: { [weak self] labels in - try? self?.storage.save(evmAddressLabels: labels) - self?.saveAddressLabels(timestamp: timestamp) - }, onError: { error in - print("Address Labels sync error: \(error)") - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onSuccess: { [weak self] labels in + try? self?.storage.save(evmAddressLabels: labels) + self?.saveAddressLabels(timestamp: timestamp) + }, onError: { error in + print("Address Labels sync error: \(error)") + }) + .disposed(by: disposeBag) } private func saveMethodLabels(timestamp: Int) { @@ -56,21 +56,19 @@ class EvmLabelManager { private func saveAddressLabels(timestamp: Int) { try? syncerStateStorage.save(value: String(timestamp), key: keyAddressLabelsTimestamp) } - } extension EvmLabelManager { - func sync() { provider.updateStatusSingle() - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onSuccess: { [weak self] status in - self?.syncMethodLabels(timestamp: status.methodLabels) - self?.syncAddressLabels(timestamp: status.addressLabels) - }, onError: { error in - print("Update Status sync error: \(error)") - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onSuccess: { [weak self] status in + self?.syncMethodLabels(timestamp: status.methodLabels) + self?.syncAddressLabels(timestamp: status.addressLabels) + }, onError: { error in + print("Update Status sync error: \(error)") + }) + .disposed(by: disposeBag) } func methodLabel(input: Data) -> String? { @@ -89,5 +87,4 @@ extension EvmLabelManager { return address.shortened } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/GuidesManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/GuidesManager.swift index 00d355c2bd..e4e13933d8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/GuidesManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/GuidesManager.swift @@ -1,7 +1,7 @@ +import Alamofire import Foundation -import RxSwift import HsToolKit -import Alamofire +import RxSwift class GuidesManager { private let networkManager: NetworkManager @@ -9,14 +9,11 @@ class GuidesManager { init(networkManager: NetworkManager) { self.networkManager = networkManager } - } extension GuidesManager { - func guideCategoriesSingle(url: URL) -> Single<[GuideCategory]> { let request = networkManager.session.request(url) return networkManager.single(request: request) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/JailbreakTestManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/JailbreakTestManager.swift index d6a647da09..2263ae12eb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/JailbreakTestManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/JailbreakTestManager.swift @@ -1,34 +1,32 @@ import UIKit class JailbreakTestManager { - var isJailbroken: Bool { if TARGET_IPHONE_SIMULATOR != 1 { // Check 1 : existence of files that are common for jailbroken devices if FileManager.default.fileExists(atPath: "/Applications/Cydia.app") - || FileManager.default.fileExists(atPath: "/Applications/FakeCarrier.app") - || FileManager.default.fileExists(atPath: "/Applications/Icy.app") - || FileManager.default.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib") - || FileManager.default.fileExists(atPath: "/bin/bash") - || FileManager.default.fileExists(atPath: "/usr/bin/sshd") - || FileManager.default.fileExists(atPath: "/etc/apt") - || FileManager.default.fileExists(atPath: "/private/var/lib/apt/") - || UIApplication.shared.canOpenURL(URL(string:"cydia://package/com.example.package")!) { + || FileManager.default.fileExists(atPath: "/Applications/FakeCarrier.app") + || FileManager.default.fileExists(atPath: "/Applications/Icy.app") + || FileManager.default.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib") + || FileManager.default.fileExists(atPath: "/bin/bash") + || FileManager.default.fileExists(atPath: "/usr/bin/sshd") + || FileManager.default.fileExists(atPath: "/etc/apt") + || FileManager.default.fileExists(atPath: "/private/var/lib/apt/") + || UIApplication.shared.canOpenURL(URL(string: "cydia://package/com.example.package")!) + { return true } // Check 2 : Reading and writing in system directories (sandbox violation) let stringToWrite = "Jailbreak Test" do { - try stringToWrite.write(toFile:"/private/JailbreakTest.txt", atomically:true, encoding:String.Encoding.utf8) - //Device is jailbroken + try stringToWrite.write(toFile: "/private/JailbreakTest.txt", atomically: true, encoding: String.Encoding.utf8) + // Device is jailbroken return true } catch { return false } - } - else { + } else { return false } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/KitCleaner.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/KitCleaner.swift index ca8dec461f..36f6426d11 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/KitCleaner.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/KitCleaner.swift @@ -6,13 +6,11 @@ class KitCleaner { init(accountManager: AccountManager) { self.accountManager = accountManager } - } extension KitCleaner { - func clear() { - let accountIds = accountManager.accounts.map { $0.id } + let accountIds = accountManager.accounts.map(\.id) DispatchQueue.global(qos: .background).async { try? BitcoinAdapter.clear(except: accountIds) @@ -26,5 +24,4 @@ extension KitCleaner { try? TronAdapter.clear(except: accountIds) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/LaunchScreenManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/LaunchScreenManager.swift index 83116a4d21..a015a20f10 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/LaunchScreenManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/LaunchScreenManager.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift class LaunchScreenManager { private let keyLaunchScreen = "launch-screen" @@ -50,5 +50,4 @@ class LaunchScreenManager { var showMarketObservable: Observable { showMarketRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/LogRecordManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/LogRecordManager.swift index 7e1542cfd4..1d220ad924 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/LogRecordManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/LogRecordManager.swift @@ -14,18 +14,18 @@ class LogRecordManager { let logs = storage.logs(context: context) return Dictionary(grouping: logs, by: { $0.context }) - .sorted { (a: (String, [LogRecord]), b: (String, [LogRecord])) in - guard let aFirst = a.1.first, let bFirst = b.1.first else { - return true - } - - return aFirst.date < bFirst.date - } - .map { (key: String, logs: [LogRecord]) -> (String, Any) in - (key, logs.map { log in - "\(Date(timeIntervalSince1970: log.date)) [\(log.levelString)]: \(log.message)" - }) - } + .sorted { (a: (String, [LogRecord]), b: (String, [LogRecord])) in + guard let aFirst = a.1.first, let bFirst = b.1.first else { + return true + } + + return aFirst.date < bFirst.date + } + .map { (key: String, logs: [LogRecord]) -> (String, Any) in + (key, logs.map { log in + "\(Date(timeIntervalSince1970: log.date)) [\(log.levelString)]: \(log.message)" + }) + } } func onBecomeActive() { @@ -40,16 +40,13 @@ class LogRecordManager { } } } - } extension LogRecordManager: ILogStorage { - - func log(date: Date, level: Logger.Level, message: String, file: String?, function: String?, line: Int?, context: [String]?) { + func log(date: Date, level: Logger.Level, message: String, file _: String?, function _: String?, line _: Int?, context: [String]?) { let context = context?.joined(separator: ":") ?? "" let record = LogRecord(date: date.timeIntervalSince1970, level: level, context: context, message: message) storage.save(logRecord: record) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/MetadataMonitor.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/MetadataMonitor.swift index ceea0d11ab..0af77f8656 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/MetadataMonitor.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/MetadataMonitor.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation import HsExtensions import HsToolKit @@ -34,11 +34,11 @@ class MetadataMonitor { } private func start() { - let predicate: NSPredicate = NSPredicate( - format: "%K = FALSE AND %K BEGINSWITH %@", - NSMetadataUbiquitousItemIsDownloadingKey, - NSMetadataItemPathKey, - url.path + let predicate = NSPredicate( + format: "%K = FALSE AND %K BEGINSWITH %@", + NSMetadataUbiquitousItemIsDownloadingKey, + NSMetadataItemPathKey, + url.path ) let metadataQuery = NSMetadataQuery() self.metadataQuery = metadataQuery @@ -90,7 +90,7 @@ class MetadataMonitor { metadataQuery?.disableUpdates() } - @objc private func handle(_ notification: Notification) { + @objc private func handle(_: Notification) { logger?.debug("=> META MONITOR: has notification!") queue.async { [weak self] in self?.initiateDownloads() @@ -140,8 +140,8 @@ class MetadataMonitor { logger?.debug("=> MONITOR : lastChangeTime : \(String(describing: fileChangedTime[url]))") if let changeTime, let lastChangeTime = fileChangedTime[url], - changeTime == lastChangeTime { - + changeTime == lastChangeTime + { logger?.debug("IGNORE FILE") return nil } @@ -171,8 +171,9 @@ class MetadataMonitor { private func resolveConflicts(for item: NSMetadataItem) throws { guard - let url = item.value(forAttribute: NSMetadataItemURLKey) as? URL, - let inConflict = item.value(forAttribute: NSMetadataUbiquitousItemHasUnresolvedConflictsKey) as? Bool else { + let url = item.value(forAttribute: NSMetadataItemURLKey) as? URL, + let inConflict = item.value(forAttribute: NSMetadataUbiquitousItemHasUnresolvedConflictsKey) as? Bool + else { throw ResolverError.invalidMetadata } guard inConflict else { @@ -200,22 +201,17 @@ class MetadataMonitor { let conflictVersions = NSFileVersion.unresolvedConflictVersionsOfItem(at: url) conflictVersions?.forEach { $0.isResolved = true } } - } extension MetadataMonitor { - var needUpdatePublisher: AnyPublisher { needUpdateSubject.eraseToAnyPublisher() } - } extension MetadataMonitor { - enum ResolverError: Error { case invalidMetadata case coordinationError(NSError) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftAdapterManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftAdapterManager.swift index 86762608a2..6e16b1f6c6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftAdapterManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftAdapterManager.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class NftAdapterManager { private let walletManager: WalletManager @@ -18,11 +18,11 @@ class NftAdapterManager { self.evmBlockchainManager = evmBlockchainManager walletManager.activeWalletDataUpdatedObservable - .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] walletData in - self?.handleAdaptersReady(wallets: walletData.wallets) - }) - .disposed(by: disposeBag) + .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onNext: { [weak self] walletData in + self?.handleAdaptersReady(wallets: walletData.wallets) + }) + .disposed(by: disposeBag) _initAdapters(wallets: walletManager.activeWallets) } @@ -45,7 +45,7 @@ class NftAdapterManager { if evmBlockchainManager.blockchain(type: nftKey.blockchainType) != nil { let evmKitWrapper = try? evmBlockchainManager.evmKitManager(blockchainType: nftKey.blockchainType).evmKitWrapper(account: nftKey.account, blockchainType: nftKey.blockchainType) - if let evmKitWrapper = evmKitWrapper, let nftKit = evmKitWrapper.nftKit { + if let evmKitWrapper, let nftKit = evmKitWrapper.nftKit { newAdapterMap[nftKey] = EvmNftAdapter(blockchainType: nftKey.blockchainType, evmKitWrapper: evmKitWrapper, nftKit: nftKit) } } else { @@ -64,11 +64,9 @@ class NftAdapterManager { self._initAdapters(wallets: wallets) } } - } extension NftAdapterManager { - var adapterMap: [NftKey: INftAdapter] { queue.sync { _adapterMap } } @@ -88,5 +86,4 @@ extension NftAdapterManager { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataManager.swift index e688c9b1d5..94bb3adafb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataManager.swift @@ -1,8 +1,8 @@ -import RxSwift -import RxRelay import HsToolKit import MarketKit import ObjectMapper +import RxRelay +import RxSwift class NftMetadataManager { private let storage: NftStorage @@ -15,18 +15,16 @@ class NftMetadataManager { self.storage = storage providerMap = [ - .ethereum: OpenSeaNftProvider(networkManager: networkManager, marketKit: marketKit) + .ethereum: OpenSeaNftProvider(networkManager: networkManager, marketKit: marketKit), ] eventProviderMap = [ - .ethereum: ReservoirNftProvider(networkManager: networkManager, marketKit: marketKit) + .ethereum: ReservoirNftProvider(networkManager: networkManager, marketKit: marketKit), ] } - } extension NftMetadataManager { - var addressMetadataObservable: Observable<(NftKey, NftAddressMetadata)> { addressMetadataRelay.asObservable() } @@ -104,13 +102,13 @@ extension NftMetadataManager { } return provider.assetsBriefMetadataSingle(nftUids: nftUids) - .catchErrorJustReturn([]) + .catchErrorJustReturn([]) } return Single.zip(singles) - .map { arrays in - arrays.reduce([], +) - } + .map { arrays in + arrays.reduce([], +) + } } func addressMetadata(nftKey: NftKey) -> NftAddressMetadata? { @@ -133,15 +131,12 @@ extension NftMetadataManager { func save(assetsBriefMetadata: [NftAssetBriefMetadata]) { storage.save(assetsBriefMetadata: assetsBriefMetadata) } - } extension NftMetadataManager { - enum ProviderError: Error { case noProviderForBlockchainType } - } enum PaginationData { @@ -150,14 +145,14 @@ enum PaginationData { var cursor: String? { switch self { - case .cursor(let value): return value + case let .cursor(value): return value default: return nil } } var page: Int? { switch self { - case .page(let value): return value + case let .page(value): return value default: return nil } } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataSyncer.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataSyncer.swift index 505758e0ca..81a8a948f1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataSyncer.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/NftMetadataSyncer.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift import HsToolKit import MarketKit +import RxSwift class NftMetadataSyncer { private let syncThreshold: TimeInterval = 1 * 60 * 60 // 1 hour @@ -18,12 +18,12 @@ class NftMetadataSyncer { self.nftStorage = nftStorage nftAdapterManager.adaptersUpdatedObservable - .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] adapterMap in - self?.sync(adapterMap: adapterMap) - self?.subscribeToAdapterRecords(adapterMap: adapterMap) - }) - .disposed(by: disposeBag) + .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onNext: { [weak self] adapterMap in + self?.sync(adapterMap: adapterMap) + self?.subscribeToAdapterRecords(adapterMap: adapterMap) + }) + .disposed(by: disposeBag) subscribeToAdapterRecords(adapterMap: nftAdapterManager.adapterMap) } @@ -33,11 +33,11 @@ class NftMetadataSyncer { for (nftKey, adapter) in adapterMap { adapter.nftRecordsObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] _ in - self?.sync(nftKey: nftKey, adapter: adapter, force: true) - }) - .disposed(by: adapterDisposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onNext: { [weak self] _ in + self?.sync(nftKey: nftKey, adapter: adapter, force: true) + }) + .disposed(by: adapterDisposeBag) } } @@ -57,13 +57,13 @@ class NftMetadataSyncer { } nftMetadataManager.addressMetadataSingle(blockchainType: nftKey.blockchainType, address: adapter.userAddress) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onSuccess: { [weak self] addressMetadata in - self?.handle(addressMetadata: addressMetadata, nftKey: nftKey) - }, onError: { error in - // todo - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onSuccess: { [weak self] addressMetadata in + self?.handle(addressMetadata: addressMetadata, nftKey: nftKey) + }, onError: { _ in + // todo + }) + .disposed(by: disposeBag) } private func handle(addressMetadata: NftAddressMetadata, nftKey: NftKey) { @@ -72,11 +72,9 @@ class NftMetadataSyncer { nftStorage.save(lastSyncTimestamp: Date().timeIntervalSince1970, nftKey: nftKey) nftMetadataManager.handle(addressMetadata: addressMetadata, nftKey: nftKey) } - } extension NftMetadataSyncer { - func sync() { sync(adapterMap: nftAdapterManager.adapterMap) } @@ -84,5 +82,4 @@ extension NftMetadataSyncer { func forceSync() { sync(adapterMap: nftAdapterManager.adapterMap, force: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/PasteboardManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/PasteboardManager.swift index 6ac4f6fb74..5c21abaca9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/PasteboardManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/PasteboardManager.swift @@ -1,8 +1,7 @@ -import UIKit import ComponentKit +import UIKit class PasteboardManager { - var value: String? { UIPasteboard.general.string } @@ -10,14 +9,11 @@ class PasteboardManager { func set(value: String) { UIPasteboard.general.string = value } - } -class CopyHelper { - +enum CopyHelper { static func copyAndNotify(value: String) { UIPasteboard.general.string = value HudHelper.instance.show(banner: .copied) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/RateAppManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/RateAppManager.swift index a4305fe451..958821af74 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/RateAppManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/RateAppManager.swift @@ -42,7 +42,7 @@ class RateAppManager { } private func showIfAllowed() { - guard isRequestAllowed && isOnBalancePage else { + guard isRequestAllowed, isOnBalancePage else { return } @@ -51,19 +51,18 @@ class RateAppManager { private func show() { if let scene = UIApplication.shared.connectedScenes - .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { - DispatchQueue.main.async { - SKStoreReviewController.requestReview(in: scene) - } + .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene + { + DispatchQueue.main.async { + SKStoreReviewController.requestReview(in: scene) } + } localStorage.rateAppLastRequestDate = Date() isRequestAllowed = false } - } extension RateAppManager { - func onBalancePageAppear() { isOnBalancePage = true showIfAllowed() @@ -107,5 +106,4 @@ extension RateAppManager { show() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/SubscriptionManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/SubscriptionManager.swift index d6d1d0fb7f..6e81905a4e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/SubscriptionManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/SubscriptionManager.swift @@ -1,7 +1,7 @@ import Foundation import HsExtensions -import MarketKit import HsToolKit +import MarketKit class SubscriptionManager { private let keyAuthToken = "subscription-auth-token" @@ -34,12 +34,10 @@ class SubscriptionManager { authToken = nil userDefaultsStorage.set(value: authToken, for: keyAuthToken) } - } extension SubscriptionManager { - - func fetch(request: () async throws -> T, onSuccess: (T) -> (), onInvalidAuthToken: () -> (), onFailure: (Error) -> ()) async throws { + func fetch(request: () async throws -> T, onSuccess: (T) -> Void, onInvalidAuthToken _: () -> Void, onFailure: (Error) -> Void) async throws { do { let result = try await request() onSuccess(result) @@ -55,10 +53,9 @@ extension SubscriptionManager { } } - func set(authToken: String) { + func set(authToken _: String) { // marketKit.set(proAuthToken: authToken) // self.authToken = authToken // localStorage.set(value: authToken, for: keyAuthToken) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/SystemInfoManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/SystemInfoManager.swift index 1d94c16d42..6b5d965413 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/SystemInfoManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/SystemInfoManager.swift @@ -1,10 +1,9 @@ import Foundation -import UIKit import LocalAuthentication import RxSwift +import UIKit class SystemInfoManager { - var appVersion: AppVersion { AppVersion(version: AppConfig.appVersion, build: AppConfig.appBuild, date: Date()) } @@ -20,5 +19,4 @@ class SystemInfoManager { var osVersion: String { UIDevice.current.systemVersion } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TestNetManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TestNetManager.swift index 4ea130e81c..2473e5bde1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TestNetManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TestNetManager.swift @@ -13,14 +13,11 @@ class TestNetManager { testNetEnabled = userDefaultsStorage.value(for: keyTestNetEnabled) ?? false } - } extension TestNetManager { - func set(testNetEnabled: Bool) { self.testNetEnabled = testNetEnabled userDefaultsStorage.set(value: testNetEnabled, for: keyTestNetEnabled) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TransactionAdapterManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TransactionAdapterManager.swift index 32adc28840..16430df670 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TransactionAdapterManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TransactionAdapterManager.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxRelay +import RxSwift class TransactionAdapterManager { private let disposeBag = DisposeBag() @@ -20,11 +20,11 @@ class TransactionAdapterManager { self.adapterFactory = adapterFactory adapterManager.adapterDataReadyObservable - .observeOn(SerialDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] adapterData in - self?.initAdapters(adapterMap: adapterData.adapterMap) - }) - .disposed(by: disposeBag) + .observeOn(SerialDispatchQueueScheduler(qos: .utility)) + .subscribe(onNext: { [weak self] adapterData in + self?.initAdapters(adapterMap: adapterData.adapterMap) + }) + .disposed(by: disposeBag) } private func initAdapters(adapterMap: [Wallet: IAdapter]) { @@ -47,7 +47,7 @@ class TransactionAdapterManager { transactionsAdapter = adapter as? ITransactionsAdapter } - if let transactionsAdapter = transactionsAdapter { + if let transactionsAdapter { newAdapterMap[source] = transactionsAdapter } } @@ -57,11 +57,9 @@ class TransactionAdapterManager { self.adaptersReadyRelay.accept(()) } } - } extension TransactionAdapterManager { - var adapterMap: [TransactionSource: ITransactionsAdapter] { queue.sync { _adapterMap } } @@ -73,5 +71,4 @@ extension TransactionAdapterManager { func adapter(for source: TransactionSource) -> ITransactionsAdapter? { queue.sync { _adapterMap[source] } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronAccountManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronAccountManager.swift index 02a2815e73..2183188219 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronAccountManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronAccountManager.swift @@ -1,6 +1,6 @@ -import RxSwift -import MarketKit import HsToolKit +import MarketKit +import RxSwift import TronKit class TronAccountManager { @@ -63,36 +63,36 @@ class TronAccountManager { for fullTransaction in fullTransactions { switch fullTransaction.decoration { - case let decoration as NativeTransactionDecoration: - if let transfer = decoration.contract as? TransferContract, transfer.ownerAddress != address { - foundTokens.insert(FoundToken(tokenType: .native)) - } - - case let decoration as UnknownTransactionDecoration: - if decoration.internalTransactions.contains(where: { $0.to == address }) { - foundTokens.insert(FoundToken(tokenType: .native)) + case let decoration as NativeTransactionDecoration: + if let transfer = decoration.contract as? TransferContract, transfer.ownerAddress != address { + foundTokens.insert(FoundToken(tokenType: .native)) + } + + case let decoration as UnknownTransactionDecoration: + if decoration.internalTransactions.contains(where: { $0.to == address }) { + foundTokens.insert(FoundToken(tokenType: .native)) + } + + for event in decoration.events { + guard let transferEvent = event as? Trc20TransferEvent else { + continue } - for event in decoration.events { - guard let transferEvent = event as? Trc20TransferEvent else { - continue - } - - if transferEvent.to == address { - let tokenType: TokenType = .eip20(address: transferEvent.contractAddress.base58) - if let fromAddress = decoration.fromAddress, fromAddress == address { - foundTokens.insert(FoundToken(tokenType: tokenType, tokenInfo: transferEvent.tokenInfo)) - } else { - suspiciousTokenTypes.insert(tokenType) - } + if transferEvent.to == address { + let tokenType: TokenType = .eip20(address: transferEvent.contractAddress.base58) + if let fromAddress = decoration.fromAddress, fromAddress == address { + foundTokens.insert(FoundToken(tokenType: tokenType, tokenInfo: transferEvent.tokenInfo)) + } else { + suspiciousTokenTypes.insert(tokenType) } } + } - default: () + default: () } } - handle(foundTokens: Array(foundTokens), suspiciousTokenTypes: Array(suspiciousTokenTypes.subtracting(foundTokens.map { $0.tokenType })), account: account, tronKit: tronKitWrapper.tronKit) + handle(foundTokens: Array(foundTokens), suspiciousTokenTypes: Array(suspiciousTokenTypes.subtracting(foundTokens.map(\.tokenType))), account: account, tronKit: tronKitWrapper.tronKit) } private func handle(foundTokens: [FoundToken], suspiciousTokenTypes: [TokenType], account: Account, tronKit: TronKit.Kit) { @@ -100,7 +100,7 @@ class TronAccountManager { return } - let queries = (foundTokens.map { $0.tokenType } + suspiciousTokenTypes).map { TokenQuery(blockchainType: blockchainType, tokenType: $0) } + let queries = (foundTokens.map(\.tokenType) + suspiciousTokenTypes).map { TokenQuery(blockchainType: blockchainType, tokenType: $0) } guard let tokens = try? marketKit.tokens(queries: queries) else { return @@ -148,7 +148,7 @@ class TronAccountManager { private func handle(tokenInfos: [TokenInfo], account: Account, tronKit: TronKit.Kit) { let existingWallets = walletManager.activeWallets - let existingTokenTypeIds = existingWallets.map { $0.token.type.id } + let existingTokenTypeIds = existingWallets.map(\.token.type.id) let newTokenInfos = tokenInfos.filter { !existingTokenTypeIds.contains($0.type.id) } guard !newTokenInfos.isEmpty else { @@ -183,11 +183,9 @@ class TronAccountManager { walletManager.save(enabledWallets: enabledWallets) } - } extension TronAccountManager { - struct TokenInfo { let type: TokenType let coinName: String @@ -208,9 +206,8 @@ extension TronAccountManager { hasher.combine(tokenType) } - static func ==(lhs: FoundToken, rhs: FoundToken) -> Bool { + static func == (lhs: FoundToken, rhs: FoundToken) -> Bool { lhs.tokenType == rhs.tokenType } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronKitManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronKitManager.swift index 5545a3b644..ad7d6c22cf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronKitManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/TronKitManager.swift @@ -1,9 +1,9 @@ import Foundation -import RxSwift -import RxRelay -import TronKit import HdWalletKit import MarketKit +import RxRelay +import RxSwift +import TronKit class TronKitManager { private let disposeBag = DisposeBag() @@ -21,7 +21,7 @@ class TronKitManager { } private func _tronKitWrapper(account: Account, blockchainType: BlockchainType) throws -> TronKitWrapper { - if let _tronKitWrapper = _tronKitWrapper, let currentAccount = currentAccount, currentAccount == account { + if let _tronKitWrapper, let currentAccount, currentAccount == account { return _tronKitWrapper } @@ -30,16 +30,16 @@ class TronKitManager { var signer: Signer? switch account.type { - case .mnemonic: - guard let seed = account.type.mnemonicSeed else { - throw KitWrapperError.mnemonicNoSeed - } - address = try Signer.address(seed: seed) - signer = try Signer.instance(seed: seed) - case let .tronAddress(value): - address = value - default: - throw AdapterError.unsupportedAccount + case .mnemonic: + guard let seed = account.type.mnemonicSeed else { + throw KitWrapperError.mnemonicNoSeed + } + address = try Signer.address(seed: seed) + signer = try Signer.instance(seed: seed) + case let .tronAddress(value): + address = value + default: + throw AdapterError.unsupportedAccount } let tronKit = try TronKit.Kit.instance( @@ -61,11 +61,9 @@ class TronKitManager { return wrapper } - } extension TronKitManager { - var tronKitCreatedObservable: Observable { tronKitCreatedRelay.asObservable() } @@ -81,7 +79,6 @@ extension TronKitManager { try _tronKitWrapper(account: account, blockchainType: blockchainType) } } - } class TronKitWrapper { @@ -96,27 +93,22 @@ class TronKitWrapper { } func send(contract: Contract, feeLimit: Int?) async throws { - guard let signer = signer else { + guard let signer else { throw SignerError.signerNotSupported } return try await tronKit.send(contract: contract, signer: signer, feeLimit: feeLimit) } - } extension TronKitManager { - enum KitWrapperError: Error { case mnemonicNoSeed } - } extension TronKitWrapper { - enum SignerError: Error { case signerNotSupported } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/UrlManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/UrlManager.swift index 1e9b3278fc..64a9ef44da 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/UrlManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/UrlManager.swift @@ -30,7 +30,7 @@ class UrlManager { return } - if let controller = controller, inApp { + if let controller, inApp { let safariViewController = SFSafariViewController(url: url, configuration: SFSafariViewController.Configuration()) safariViewController.modalPresentationStyle = .pageSheet controller.present(safariViewController, animated: true) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletConnectSessionManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletConnectSessionManager.swift index 4c716f4ce5..04dab03083 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletConnectSessionManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletConnectSessionManager.swift @@ -67,9 +67,7 @@ class WalletConnectSessionManager { let currentSessions = allSessions let allDbSessions = storage.sessions(accountId: nil) - let dbTopics = allDbSessions.map { - $0.topic - } + let dbTopics = allDbSessions.map(\.topic) let newSessions = currentSessions.filter { session in !dbTopics.contains(session.topic) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletManager.swift index c1663c19c3..fa993d5991 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Managers/WalletManager.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class WalletManager { private let accountManager: AccountManager @@ -38,7 +38,7 @@ class WalletManager { } do { - cachedActiveWalletData = WalletData(wallets: try storage.wallets(account: activeAccount), account: activeAccount) + cachedActiveWalletData = try WalletData(wallets: storage.wallets(account: activeAccount), account: activeAccount) } catch { // todo cachedActiveWalletData = WalletData(wallets: [], account: activeAccount) @@ -50,11 +50,9 @@ class WalletManager { private func reloadWallets() { queue.async { [weak self] in self?._reloadWallets() } } - } extension WalletManager { - var activeWalletData: WalletData { queue.sync { cachedActiveWalletData } } @@ -101,14 +99,11 @@ extension WalletManager { func clearWallets() { storage.clearWallets() } - } extension WalletManager { - struct WalletData { let wallets: [Wallet] let account: Account? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Protocols.swift b/UnstoppableWallet/UnstoppableWallet/Core/Protocols.swift index f6897fab0e..a9f8ffd6cb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Protocols.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Protocols.swift @@ -1,17 +1,16 @@ +import Alamofire +import BigInt import Combine -import UIKit -import RxSwift -import GRDB -import UniswapKit import EvmKit -import TronKit -import ThemeKit -import Alamofire +import GRDB import HsToolKit import MarketKit -import BigInt +import RxSwift +import ThemeKit +import TronKit +import UIKit +import UniswapKit import ZcashLightClientKit -import HsToolKit protocol IBaseAdapter { var isMainNet: Bool { get } @@ -40,7 +39,6 @@ protocol IDepositAdapter: IBaseAdapter { } extension IDepositAdapter { - var receiveAddressStatus: DataStatus { .completed(receiveAddress) } @@ -48,7 +46,6 @@ extension IDepositAdapter { var receiveAddressPublisher: AnyPublisher, Never> { Just(receiveAddressStatus).eraseToAnyPublisher() } - } protocol ITransactionsAdapter { @@ -154,8 +151,8 @@ protocol IFeeRateProvider { } protocol IAppManager { - var didBecomeActiveObservable: Observable<()> { get } - var willEnterForegroundObservable: Observable<()> { get } + var didBecomeActiveObservable: Observable { get } + var willEnterForegroundObservable: Observable { get } } protocol IPresentDelegate: AnyObject { @@ -164,11 +161,9 @@ protocol IPresentDelegate: AnyObject { } extension IPresentDelegate { - - func push(viewController: UIViewController) { - //might be implemented by delegate + func push(viewController _: UIViewController) { + // might be implemented by delegate } - } protocol Warning {} diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift index 8fce8ff167..8945ca26a2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift @@ -1,6 +1,6 @@ import Foundation -import UIKit import MarketKit +import UIKit struct AppConfig { static let label = "io.horizontalsystems.unstoppable" @@ -36,7 +36,7 @@ struct AppConfig { .gnosis: "0xA24c159C7f1E4A04dab7c364C2A8b87b3dBa4cd1", .fantom: "0xA24c159C7f1E4A04dab7c364C2A8b87b3dBa4cd1", .tron: "TQzANCd363w5CjRWDtswm8Y5nFPAdnwekF", - .solana: "5gattKnvu5f1NDHBuZ6VfDXjRrJa9UcAArkZ3ys3e82F" + .solana: "5gattKnvu5f1NDHBuZ6VfDXjRrJa9UcAArkZ3ys3e82F", ] static var appVersion: String { @@ -160,5 +160,4 @@ struct AppConfig { static var blockchairApiKey: String { (Bundle.main.object(forInfoDictionaryKey: "BlockchairApiKey") as? String) ?? "" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/CurrentDateProvider.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/CurrentDateProvider.swift index 9eb6548b2b..5ce146141c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/CurrentDateProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/CurrentDateProvider.swift @@ -1,9 +1,7 @@ import Foundation class CurrentDateProvider { - var currentDate: Date { Date() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeCoinProvider.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeCoinProvider.swift index 0e9b29dc0f..127ca916fe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeCoinProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeCoinProvider.swift @@ -6,11 +6,9 @@ class FeeCoinProvider { init(marketKit: Kit) { self.marketKit = marketKit } - } extension FeeCoinProvider { - func feeToken(token: Token) -> Token? { switch token.type { case .eip20, .bep2: @@ -20,5 +18,4 @@ extension FeeCoinProvider { return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeRateProvider.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeRateProvider.swift index ab2d1f4b8a..70ec91e3c1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeRateProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/FeeRateProvider.swift @@ -1,5 +1,5 @@ -import Foundation import FeeRateKit +import Foundation import RxSwift class FeeRateProvider { @@ -7,10 +7,10 @@ class FeeRateProvider { init() { let providerConfig = FeeProviderConfig( - ethEvmUrl: FeeProviderConfig.infuraUrl(projectId: AppConfig.infuraCredentials.id), - ethEvmAuth: AppConfig.infuraCredentials.secret, - bscEvmUrl: FeeProviderConfig.defaultBscEvmUrl, - mempoolSpaceUrl: AppConfig.mempoolSpaceUrl + ethEvmUrl: FeeProviderConfig.infuraUrl(projectId: AppConfig.infuraCredentials.id), + ethEvmAuth: AppConfig.infuraCredentials.secret, + bscEvmUrl: FeeProviderConfig.defaultBscEvmUrl, + mempoolSpaceUrl: AppConfig.mempoolSpaceUrl ) feeRateKit = FeeRateKit.Kit.instance(providerConfig: providerConfig, minLogLevel: .error) } @@ -40,16 +40,13 @@ class FeeRateProvider { fileprivate func bitcoinFeeRate() async throws -> MempoolSpaceProvider.RecommendedFees { try await feeRateKit.bitcoin() } - } extension FeeRateProvider { - struct FeeRates { let recommended: Int let minimum: Int } - } class BitcoinFeeRateProvider: IFeeRateProvider { @@ -63,7 +60,6 @@ class BitcoinFeeRateProvider: IFeeRateProvider { let rates = try await feeRateProvider.bitcoinFeeRate() return .init(recommended: rates.halfHourFee, minimum: rates.minimumFee) } - } class LitecoinFeeRateProvider: IFeeRateProvider { @@ -76,7 +72,6 @@ class LitecoinFeeRateProvider: IFeeRateProvider { func feeRates() async throws -> FeeRateProvider.FeeRates { .init(recommended: feeRateProvider.litecoinFeeRate, minimum: 0) } - } class BitcoinCashFeeRateProvider: IFeeRateProvider { @@ -89,15 +84,12 @@ class BitcoinCashFeeRateProvider: IFeeRateProvider { func feeRates() async throws -> FeeRateProvider.FeeRates { .init(recommended: feeRateProvider.bitcoinCashFeeRate, minimum: 0) } - } class ECashFeeRateProvider: IFeeRateProvider { - func feeRates() async throws -> FeeRateProvider.FeeRates { .init(recommended: 1, minimum: 0) } - } class DashFeeRateProvider: IFeeRateProvider { @@ -110,11 +102,10 @@ class DashFeeRateProvider: IFeeRateProvider { func feeRates() async throws -> FeeRateProvider.FeeRates { .init(recommended: feeRateProvider.dashFeeRate, minimum: 0) } - } private func ceil(_ value: Int, multiply: Double?) -> Int { - guard let multiply = multiply else { + guard let multiply else { return value } return Int(ceil(Double(value) * multiply)) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/HsLabelProvider.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/HsLabelProvider.swift index 4c33fb5bb6..71a8293f1b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/HsLabelProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/HsLabelProvider.swift @@ -1,8 +1,8 @@ +import Alamofire import Foundation -import RxSwift -import ObjectMapper import HsToolKit -import Alamofire +import ObjectMapper +import RxSwift class HsLabelProvider { private let networkManager: NetworkManager @@ -13,11 +13,9 @@ class HsLabelProvider { self.networkManager = networkManager headers = AppConfig.hsProviderApiKey.flatMap { HTTPHeaders([HTTPHeader(name: "apikey", value: $0)]) } } - } extension HsLabelProvider { - func updateStatusSingle() -> Single { let request = networkManager.session.request("\(apiUrl)/v1/status/updates", headers: headers) return networkManager.single(request: request) @@ -32,5 +30,4 @@ extension HsLabelProvider { let request = networkManager.session.request("\(apiUrl)/v1/addresses/labels", headers: headers) return networkManager.single(request: request) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/OpenSeaNftProvider.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/OpenSeaNftProvider.swift index 03d4678f9c..8acd82f7d1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/OpenSeaNftProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/OpenSeaNftProvider.swift @@ -1,9 +1,9 @@ +import Alamofire import Foundation -import RxSwift import HsToolKit import MarketKit import ObjectMapper -import Alamofire +import RxSwift class OpenSeaNftProvider { private let baseUrl = "https://api.opensea.io/api/v1" @@ -22,7 +22,7 @@ class OpenSeaNftProvider { headers = HTTPHeaders([ HTTPHeader.userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"), - HTTPHeader(name: "X-API-KEY", value: AppConfig.openSeaApiKey) + HTTPHeader(name: "X-API-KEY", value: AppConfig.openSeaApiKey), ]) } @@ -31,7 +31,7 @@ class OpenSeaNftProvider { "asset_owner": address, "limit": collectionLimit, "offset": offset, - "format": "json" + "format": "json", ] let request = networkManager.session.request("\(baseUrl)/collections", parameters: parameters, encoding: encoding, headers: headers) @@ -42,18 +42,18 @@ class OpenSeaNftProvider { var parameters: Parameters = [ "include_orders": true, "limit": assetLimit, - "format": "json" + "format": "json", ] - if let address = address { + if let address { parameters["owner"] = address } - if let collection = collection { + if let collection { parameters["collection"] = collection } - if let cursor = cursor { + if let cursor { parameters["cursor"] = cursor } @@ -63,10 +63,10 @@ class OpenSeaNftProvider { private func assetsSingle(references: [AssetReference]) -> Single { let parameters: Parameters = [ - "asset_contract_addresses": references.map { $0.contractAddress }, - "token_ids": references.map { $0.tokenId }, + "asset_contract_addresses": references.map(\.contractAddress), + "token_ids": references.map(\.tokenId), "limit": assetLimit, - "format": "json" + "format": "json", ] let request = networkManager.session.request("\(baseUrl)/assets", parameters: parameters, encoding: encoding, headers: headers) @@ -76,7 +76,7 @@ class OpenSeaNftProvider { private func assetSingle(contractAddress: String, tokenId: String) -> Single { let parameters: Parameters = [ "include_orders": true, - "format": "json" + "format": "json", ] let request = networkManager.session.request("\(baseUrl)/asset/\(contractAddress)/\(tokenId)", parameters: parameters, encoding: encoding, headers: headers) @@ -85,7 +85,7 @@ class OpenSeaNftProvider { private func collectionSingle(slug: String) -> Single { let parameters: Parameters = [ - "format": "json" + "format": "json", ] let request = networkManager.session.request("\(baseUrl)/collection/\(slug)", parameters: parameters, encoding: encoding, headers: headers) @@ -94,36 +94,36 @@ class OpenSeaNftProvider { private func recursiveCollectionsSingle(address: String, offset: Int = 0, allCollections: [CollectionResponse] = []) -> Single<[CollectionResponse]> { collectionsSingle(address: address, offset: offset) - .flatMap { [weak self] collections in - guard let strongSelf = self else { - throw ProviderError.weakReference - } - - let allCollections = allCollections + collections - - if collections.count == strongSelf.collectionLimit { - return strongSelf.recursiveCollectionsSingle(address: address, offset: allCollections.count, allCollections: allCollections) - } else { - return Single.just(allCollections) - } + .flatMap { [weak self] collections in + guard let strongSelf = self else { + throw ProviderError.weakReference } + + let allCollections = allCollections + collections + + if collections.count == strongSelf.collectionLimit { + return strongSelf.recursiveCollectionsSingle(address: address, offset: allCollections.count, allCollections: allCollections) + } else { + return Single.just(allCollections) + } + } } private func recursiveAssetsSingle(address: String, cursor: String? = nil, allAssets: [AssetResponse] = []) -> Single<[AssetResponse]> { assetsSingle(address: address, cursor: cursor) - .flatMap { [weak self] response in - guard let strongSelf = self else { - throw ProviderError.weakReference - } - - let allAssets = allAssets + response.assets - - if let cursor = response.cursor { - return strongSelf.recursiveAssetsSingle(address: address, cursor: cursor, allAssets: allAssets) - } else { - return Single.just(allAssets) - } + .flatMap { [weak self] response in + guard let strongSelf = self else { + throw ProviderError.weakReference + } + + let allAssets = allAssets + response.assets + + if let cursor = response.cursor { + return strongSelf.recursiveAssetsSingle(address: address, cursor: cursor, allAssets: allAssets) + } else { + return Single.just(allAssets) } + } } private func collections(blockchainType: BlockchainType, responses: [CollectionResponse]) -> [NftCollectionMetadata] { @@ -138,36 +138,36 @@ class OpenSeaNftProvider { let baseToken = baseToken ?? (try? marketKit.token(query: TokenQuery(blockchainType: blockchainType, tokenType: .native))) return NftCollectionMetadata( - blockchainType: blockchainType, - providerUid: response.slug, - contracts: response.contracts.map { contract(response: $0) }, - name: response.name, - description: response.description, - imageUrl: response.largeImageUrl, - thumbnailImageUrl: response.imageUrl, - externalLink: response.externalUrl, - discordLink: response.discordUrl, - twitterUsername: response.twitterUsername, - count: response.stats?.count, - ownerCount: response.stats?.ownerCount, - totalSupply: response.stats?.totalSupply, - totalVolume: response.stats?.totalVolume, - floorPrice: nftPrice(token: baseToken, value: response.stats?.floorPrice, shift: false), - marketCap: nftPrice(token: baseToken, value: response.stats?.marketCap, shift: false), - royalty: response.devSellerFeeBasisPoints / 100, - inceptionDate: response.createdDate, - volume1d: nftPrice(token: baseToken, value: response.stats?.oneDayVolume, shift: false), - change1d: response.stats?.oneDayChange, - sales1d: response.stats?.oneDaySales, - averagePrice1d: nftPrice(token: baseToken, value: response.stats?.oneDayAveragePrice, shift: false), - volume7d: nftPrice(token: baseToken, value: response.stats?.sevenDayVolume, shift: false), - change7d: response.stats?.sevenDayChange, - sales7d: response.stats?.sevenDaySales, - averagePrice7d: nftPrice(token: baseToken, value: response.stats?.sevenDayAveragePrice, shift: false), - volume30d: nftPrice(token: baseToken, value: response.stats?.thirtyDayVolume, shift: false), - change30d: response.stats?.thirtyDayChange, - sales30d: response.stats?.thirtyDaySales, - averagePrice30d: nftPrice(token: baseToken, value: response.stats?.thirtyDayAveragePrice, shift: false) + blockchainType: blockchainType, + providerUid: response.slug, + contracts: response.contracts.map { contract(response: $0) }, + name: response.name, + description: response.description, + imageUrl: response.largeImageUrl, + thumbnailImageUrl: response.imageUrl, + externalLink: response.externalUrl, + discordLink: response.discordUrl, + twitterUsername: response.twitterUsername, + count: response.stats?.count, + ownerCount: response.stats?.ownerCount, + totalSupply: response.stats?.totalSupply, + totalVolume: response.stats?.totalVolume, + floorPrice: nftPrice(token: baseToken, value: response.stats?.floorPrice, shift: false), + marketCap: nftPrice(token: baseToken, value: response.stats?.marketCap, shift: false), + royalty: response.devSellerFeeBasisPoints / 100, + inceptionDate: response.createdDate, + volume1d: nftPrice(token: baseToken, value: response.stats?.oneDayVolume, shift: false), + change1d: response.stats?.oneDayChange, + sales1d: response.stats?.oneDaySales, + averagePrice1d: nftPrice(token: baseToken, value: response.stats?.oneDayAveragePrice, shift: false), + volume7d: nftPrice(token: baseToken, value: response.stats?.sevenDayVolume, shift: false), + change7d: response.stats?.sevenDayChange, + sales7d: response.stats?.sevenDaySales, + averagePrice7d: nftPrice(token: baseToken, value: response.stats?.sevenDayAveragePrice, shift: false), + volume30d: nftPrice(token: baseToken, value: response.stats?.thirtyDayVolume, shift: false), + change30d: response.stats?.thirtyDayChange, + sales30d: response.stats?.thirtyDaySales, + averagePrice30d: nftPrice(token: baseToken, value: response.stats?.thirtyDayAveragePrice, shift: false) ) } @@ -198,11 +198,11 @@ class OpenSeaNftProvider { let response = responses.first { $0.contract.address == nftUid.contractAddress && $0.tokenId == nftUid.tokenId } return NftAssetBriefMetadata( - nftUid: nftUid, - providerCollectionUid: response?.collection.slug, - name: response?.name, - imageUrl: response?.imageUrl, - previewImageUrl: response?.imagePreviewUrl + nftUid: nftUid, + providerCollectionUid: response?.collection.slug, + name: response?.name, + imageUrl: response?.imageUrl, + previewImageUrl: response?.imagePreviewUrl ) } } @@ -210,7 +210,7 @@ class OpenSeaNftProvider { private func asset(blockchainType: BlockchainType, response: AssetResponse, tokenMap: [String: Token]? = nil) -> NftAssetMetadata { let map: [String: Token] - if let tokenMap = tokenMap { + if let tokenMap { map = tokenMap } else { var addresses = Set() @@ -248,49 +248,49 @@ class OpenSeaNftProvider { } return NftAssetMetadata( - nftUid: .evm(blockchainType: blockchainType, contractAddress: response.contract.address, tokenId: response.tokenId), - providerCollectionUid: response.collection.slug, - name: response.name, - imageUrl: response.imageUrl, - previewImageUrl: response.imagePreviewUrl, - description: response.description, - contract: contract(response: response.contract), - externalLink: response.externalLink, - providerLink: response.permalink, - traits: response.traits.map { NftAssetMetadata.Trait(type: $0.type, value: $0.value, count: $0.count) }, - providerTraitLink: "https://opensea.io/assets/\(response.collection.slug)?search[stringTraits][0][name]=$traitName&search[stringTraits][0][values][0]=$traitValue&search[sortAscending]=true&search[sortBy]=PRICE", - lastSalePrice: response.lastSale.flatMap { nftPrice(token: map[$0.paymentTokenAddress.lowercased()], value: $0.totalPrice, shift: true) }, - offers: offers, - saleInfo: saleInfo + nftUid: .evm(blockchainType: blockchainType, contractAddress: response.contract.address, tokenId: response.tokenId), + providerCollectionUid: response.collection.slug, + name: response.name, + imageUrl: response.imageUrl, + previewImageUrl: response.imagePreviewUrl, + description: response.description, + contract: contract(response: response.contract), + externalLink: response.externalLink, + providerLink: response.permalink, + traits: response.traits.map { NftAssetMetadata.Trait(type: $0.type, value: $0.value, count: $0.count) }, + providerTraitLink: "https://opensea.io/assets/\(response.collection.slug)?search[stringTraits][0][name]=$traitName&search[stringTraits][0][values][0]=$traitValue&search[sortAscending]=true&search[sortBy]=PRICE", + lastSalePrice: response.lastSale.flatMap { nftPrice(token: map[$0.paymentTokenAddress.lowercased()], value: $0.totalPrice, shift: true) }, + offers: offers, + saleInfo: saleInfo ) } private func saleInfo(type: NftAssetMetadata.SaleType, orders: [OrderResponse], map: [String: Token]) -> NftAssetMetadata.SaleInfo { NftAssetMetadata.SaleInfo( - type: type, - listings: orders.compactMap { order -> NftAssetMetadata.SaleListing? in - guard let consideration = order.considerations.first, let token = map[consideration.token.lowercased()] else { - return nil - } - - return NftAssetMetadata.SaleListing( - untilDate: order.expirationDate, - price: nftPrice(token: token, value: order.currentPrice, shift: true) - ) + type: type, + listings: orders.compactMap { order -> NftAssetMetadata.SaleListing? in + guard let consideration = order.considerations.first, let token = map[consideration.token.lowercased()] else { + return nil } + + return NftAssetMetadata.SaleListing( + untilDate: order.expirationDate, + price: nftPrice(token: token, value: order.currentPrice, shift: true) + ) + } ) } private func contract(response: AssetContractResponse) -> NftContractMetadata { NftContractMetadata( - address: response.address, - name: response.name, - schema: response.schemaName + address: response.address, + name: response.name, + schema: response.schemaName ) } private func nftPrice(token: Token?, value: Decimal?, shift: Bool) -> NftPrice? { - guard let token = token, let value = value else { + guard let token, let value else { return nil } @@ -299,8 +299,8 @@ class OpenSeaNftProvider { private func nftPrice(token: Token, value: Decimal, shift: Bool) -> NftPrice { NftPrice( - token: token, - value: shift ? Decimal(sign: .plus, exponent: -token.decimals, significand: value) : value + token: token, + value: shift ? Decimal(sign: .plus, exponent: -token.decimals, significand: value) : value ) } @@ -322,7 +322,7 @@ class OpenSeaNftProvider { switch token.type { case .native: map[zeroAddress] = token - case .eip20(let address): + case let .eip20(address): map[address.lowercased()] = token default: () @@ -334,11 +334,9 @@ class OpenSeaNftProvider { return [:] } } - } extension OpenSeaNftProvider: INftProvider { - var title: String { "OpenSea" } @@ -365,30 +363,30 @@ extension OpenSeaNftProvider: INftProvider { } return Single.zip(collectionsSingle, assetsSingle) - .map { collections, assets in - let collectionsMetadata = collections.map { collection in - NftCollectionShortMetadata( - providerUid: collection.providerUid, - name: collection.name, - thumbnailImageUrl: collection.imageUrl ?? collection.thumbnailImageUrl, - averagePrice7d: collection.averagePrice7d, - averagePrice30d: collection.averagePrice30d - ) - } - - let assetsMetadata = assets.map { asset in - NftAssetShortMetadata( - nftUid: asset.nftUid, - providerCollectionUid: asset.providerCollectionUid, - name: asset.name, - previewImageUrl: asset.previewImageUrl, - onSale: asset.saleInfo != nil, - lastSalePrice: asset.lastSalePrice - ) - } - - return NftAddressMetadata(collections: collectionsMetadata, assets: assetsMetadata) + .map { collections, assets in + let collectionsMetadata = collections.map { collection in + NftCollectionShortMetadata( + providerUid: collection.providerUid, + name: collection.name, + thumbnailImageUrl: collection.imageUrl ?? collection.thumbnailImageUrl, + averagePrice7d: collection.averagePrice7d, + averagePrice30d: collection.averagePrice30d + ) } + + let assetsMetadata = assets.map { asset in + NftAssetShortMetadata( + nftUid: asset.nftUid, + providerCollectionUid: asset.providerCollectionUid, + name: asset.name, + previewImageUrl: asset.previewImageUrl, + onSale: asset.saleInfo != nil, + lastSalePrice: asset.lastSalePrice + ) + } + + return NftAddressMetadata(collections: collectionsMetadata, assets: assetsMetadata) + } } func assetsBriefMetadataSingle(nftUids: [NftUid]) -> Single<[NftAssetBriefMetadata]> { @@ -397,7 +395,7 @@ extension OpenSeaNftProvider: INftProvider { } let chunkedReferences = stride(from: 0, to: references.count, by: assetLimit).map { - Array(references[$0.. Single<(NftAssetMetadata, NftCollectionMetadata)> { Single.zip( - assetSingle(contractAddress: nftUid.contractAddress, tokenId: nftUid.tokenId), - collectionSingle(slug: providerCollectionUid) + assetSingle(contractAddress: nftUid.contractAddress, tokenId: nftUid.tokenId), + collectionSingle(slug: providerCollectionUid) ) - .map { [weak self] assetResponse, collectionResponse in - guard let strongSelf = self else { - throw ProviderError.weakReference - } - - return ( - strongSelf.asset(blockchainType: nftUid.blockchainType, response: assetResponse), - strongSelf.collection(blockchainType: nftUid.blockchainType, response: collectionResponse.collection) - ) - } + .map { [weak self] assetResponse, collectionResponse in + guard let strongSelf = self else { + throw ProviderError.weakReference + } + + return ( + strongSelf.asset(blockchainType: nftUid.blockchainType, response: assetResponse), + strongSelf.collection(blockchainType: nftUid.blockchainType, response: collectionResponse.collection) + ) + } } func collectionAssetsMetadataSingle(blockchainType: BlockchainType, providerCollectionUid: String, paginationData: PaginationData?) -> Single<([NftAssetMetadata], PaginationData?)> { assetsSingle(collection: providerCollectionUid, cursor: paginationData?.cursor) - .map { [weak self] response in - guard let strongSelf = self else { - throw ProviderError.weakReference - } + .map { [weak self] response in + guard let strongSelf = self else { + throw ProviderError.weakReference + } - let assets = strongSelf.assets(blockchainType: blockchainType, responses: response.assets) + let assets = strongSelf.assets(blockchainType: blockchainType, responses: response.assets) - return (assets, response.cursor.map { .cursor(value: $0) }) - } + return (assets, response.cursor.map { .cursor(value: $0) }) + } } func collectionMetadataSingle(blockchainType: BlockchainType, providerUid: String) -> Single { collectionSingle(slug: providerUid) - .map { [weak self] response in - guard let strongSelf = self else { - throw ProviderError.weakReference - } - - return strongSelf.collection(blockchainType: blockchainType, response: response.collection) + .map { [weak self] response in + guard let strongSelf = self else { + throw ProviderError.weakReference } - } + return strongSelf.collection(blockchainType: blockchainType, response: response.collection) + } + } } extension OpenSeaNftProvider { - private struct CollectionResponse: ImmutableMappable { private static let reusableDateFormatter: DateFormatter = { let dateFormatter = DateFormatter(withFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSSSZ", locale: "en_US_POSIX") @@ -677,5 +673,4 @@ extension OpenSeaNftProvider { enum ProviderError: Error { case weakReference } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/ReservoirNftProvider.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/ReservoirNftProvider.swift index 7b7b41be69..ce24a7bb31 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/ReservoirNftProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/Nft/ReservoirNftProvider.swift @@ -1,9 +1,9 @@ +import Alamofire import Foundation -import RxSwift import HsToolKit import MarketKit import ObjectMapper -import Alamofire +import RxSwift class ReservoirNftProvider { private let baseUrl = "https://api.reservoir.tools" @@ -22,11 +22,11 @@ class ReservoirNftProvider { return responses.map { response in NftEventMetadata( - nftUid: response.tokenId.map { .evm(blockchainType: blockchainType, contractAddress: response.contract, tokenId: $0) }, - previewImageUrl: response.tokenImage, - type: eventType(apiEventType: response.type), - date: response.date, - price: nftPrice(token: token, value: response.price) + nftUid: response.tokenId.map { .evm(blockchainType: blockchainType, contractAddress: response.contract, tokenId: $0) }, + previewImageUrl: response.tokenImage, + type: eventType(apiEventType: response.type), + date: response.date, + price: nftPrice(token: token, value: response.price) ) } } catch { @@ -35,7 +35,7 @@ class ReservoirNftProvider { } private func nftPrice(token: Token?, value: Decimal?) -> NftPrice? { - guard let token = token, let value = value else { + guard let token, let value else { return nil } @@ -43,7 +43,7 @@ class ReservoirNftProvider { } private func apiEventType(eventType: NftEventMetadata.EventType?) -> String? { - guard let eventType = eventType else { + guard let eventType else { return nil } @@ -59,7 +59,7 @@ class ReservoirNftProvider { } private func eventType(apiEventType: String?) -> NftEventMetadata.EventType? { - guard let apiEventType = apiEventType else { + guard let apiEventType else { return nil } @@ -74,11 +74,9 @@ class ReservoirNftProvider { default: return nil } } - } extension ReservoirNftProvider: INftEventProvider { - func assetEventsMetadataSingle(nftUid: NftUid, eventType: NftEventMetadata.EventType?, paginationData: PaginationData?) -> Single<([NftEventMetadata], PaginationData?)> { var parameters: Parameters = [:] @@ -93,20 +91,20 @@ extension ReservoirNftProvider: INftEventProvider { let request = networkManager.session.request("\(baseUrl)/tokens/\(nftUid.contractAddress):\(nftUid.tokenId)/activity/v4", parameters: parameters) return networkManager.single(request: request) - .map { [weak self] (response: EventsResponse) in - guard let strongSelf = self else { - throw ProviderError.weakReference - } + .map { [weak self] (response: EventsResponse) in + guard let strongSelf = self else { + throw ProviderError.weakReference + } - let events = strongSelf.events(blockchainType: nftUid.blockchainType, responses: response.events) + let events = strongSelf.events(blockchainType: nftUid.blockchainType, responses: response.events) - return (events, response.cursor.map { .cursor(value: $0) }) - } + return (events, response.cursor.map { .cursor(value: $0) }) + } } func collectionEventsMetadataSingle(blockchainType: BlockchainType, contractAddress: String, eventType: NftEventMetadata.EventType?, paginationData: PaginationData?) -> Single<([NftEventMetadata], PaginationData?)> { var parameters: Parameters = [ - "collection": contractAddress + "collection": contractAddress, ] if let eventType = apiEventType(eventType: eventType) { @@ -120,21 +118,19 @@ extension ReservoirNftProvider: INftEventProvider { let request = networkManager.session.request("\(baseUrl)/collections/activity/v5", parameters: parameters) return networkManager.single(request: request) - .map { [weak self] (response: EventsResponse) in - guard let strongSelf = self else { - throw ProviderError.weakReference - } + .map { [weak self] (response: EventsResponse) in + guard let strongSelf = self else { + throw ProviderError.weakReference + } - let events = strongSelf.events(blockchainType: blockchainType, responses: response.events) + let events = strongSelf.events(blockchainType: blockchainType, responses: response.events) - return (events, response.cursor.map { .cursor(value: $0) }) - } + return (events, response.cursor.map { .cursor(value: $0) }) + } } - } extension ReservoirNftProvider { - private struct EventResponse: ImmutableMappable { let contract: String let tokenId: String? @@ -166,5 +162,4 @@ extension ReservoirNftProvider { enum ProviderError: Error { case weakReference } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountRecordStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountRecordStorage.swift index ac8942c329..0827000fe3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountRecordStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountRecordStorage.swift @@ -6,11 +6,9 @@ class AccountRecordStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension AccountRecordStorage { - var all: [AccountRecord] { try! dbPool.read { db in try AccountRecord.fetchAll(db) @@ -34,5 +32,4 @@ extension AccountRecordStorage { try AccountRecord.deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountStorage.swift index aa32c712eb..4fd6bfed69 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AccountStorage.swift @@ -1,7 +1,7 @@ -import Foundation import EvmKit -import TronKit +import Foundation import HdWalletKit +import TronKit class AccountStorage { private let keychainStorage: KeychainStorage @@ -34,7 +34,7 @@ class AccountStorage { } let compliant = record.bip39Compliant ?? ( - Mnemonic.seed(mnemonic: words, passphrase: salt) == Mnemonic.seedNonStandard(mnemonic: words, passphrase: salt) + Mnemonic.seed(mnemonic: words, passphrase: salt) == Mnemonic.seedNonStandard(mnemonic: words, passphrase: salt) ) type = .mnemonic(words: words, salt: salt, bip39Compliant: compliant) @@ -87,13 +87,13 @@ class AccountStorage { } return Account( - id: id, - level: record.level, - name: record.name, - type: type, - origin: origin, - backedUp: record.backedUp, - fileBackedUp: record.fileBackedUp + id: id, + level: record.level, + name: record.name, + type: type, + origin: origin, + backedUp: record.backedUp, + fileBackedUp: record.fileBackedUp ) } @@ -107,27 +107,27 @@ class AccountStorage { var bip39Compliant: Bool? switch account.type { - case .mnemonic(let words, let salt, let compliant): + case let .mnemonic(words, salt, compliant): typeName = .mnemonic wordsKey = try store(stringArray: words, id: id, typeName: typeName, keyName: .words) saltKey = try store(salt, id: id, typeName: typeName, keyName: .salt) bip39Compliant = compliant - case .evmPrivateKey(let data): + case let .evmPrivateKey(data): typeName = .evmPrivateKey dataKey = try store(data: data, id: id, typeName: typeName, keyName: .data) - case .evmAddress(let address): + case let .evmAddress(address): typeName = .evmAddress dataKey = try store(data: address.raw, id: id, typeName: typeName, keyName: .data) - case .tronAddress(let address): + case let .tronAddress(address): typeName = .tronAddress dataKey = try store(data: address.raw, id: id, typeName: typeName, keyName: .data) - case .tonAddress(let address): + case let .tonAddress(address): typeName = .tonAddress dataKey = address - case .hdExtendedKey(let key): + case let .hdExtendedKey(key): typeName = .hdExtendedKey dataKey = try store(data: key.serialized, id: id, typeName: typeName, keyName: .data) - case .cex(let cexAccount): + case let .cex(cexAccount): typeName = .cex if let data = cexAccount.uniqueId.data(using: .utf8) { dataKey = try store(data: data, id: id, typeName: typeName, keyName: .data) @@ -135,17 +135,17 @@ class AccountStorage { } return AccountRecord( - id: id, - level: account.level, - name: account.name, - type: typeName.rawValue, - origin: account.origin.rawValue, - backedUp: account.backedUp, - fileBackedUp: account.fileBackedUp, - wordsKey: wordsKey, - saltKey: saltKey, - dataKey: dataKey, - bip39Compliant: bip39Compliant + id: id, + level: account.level, + name: account.name, + type: typeName.rawValue, + origin: account.origin.rawValue, + backedUp: account.backedUp, + fileBackedUp: account.fileBackedUp, + wordsKey: wordsKey, + saltKey: saltKey, + dataKey: dataKey, + bip39Compliant: bip39Compliant ) } @@ -179,7 +179,7 @@ class AccountStorage { try store(stringArray.joined(separator: ","), id: id, typeName: typeName, keyName: keyName) } - private func store(_ value: T, id: String, typeName: TypeName, keyName: KeyName) throws -> String { + private func store(_ value: some LosslessStringConvertible, id: String, typeName: TypeName, keyName: KeyName) throws -> String { let key = secureKey(id: id, typeName: typeName, keyName: keyName) try keychainStorage.set(value: value, for: key) return key @@ -205,11 +205,9 @@ class AccountStorage { let key = secureKey(id: id, typeName: typeName, keyName: keyName) return keychainStorage.value(for: key) } - } extension AccountStorage { - var allAccounts: [Account] { storage.all.compactMap { createAccount(record: $0) } } @@ -242,11 +240,9 @@ extension AccountStorage { func clear() { storage.clear() } - } extension AccountStorage { - private enum TypeName: String { case mnemonic case evmPrivateKey @@ -262,5 +258,4 @@ extension AccountStorage { case salt case data } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/ActiveAccountStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/ActiveAccountStorage.swift index 5469d59b53..101454e4ac 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/ActiveAccountStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/ActiveAccountStorage.swift @@ -6,11 +6,9 @@ class ActiveAccountStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension ActiveAccountStorage { - func activeAccountId(level: Int) -> String? { try? dbPool.read { db in try ActiveAccount.filter(ActiveAccount.Columns.level == level).fetchOne(db)?.accountId @@ -26,5 +24,4 @@ extension ActiveAccountStorage { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionRecordStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionRecordStorage.swift index b43f1de54c..8f1ffcd2b0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionRecordStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionRecordStorage.swift @@ -6,11 +6,9 @@ class AppVersionRecordStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension AppVersionRecordStorage { - var appVersionRecords: [AppVersionRecord] { try! dbPool.read { db in try AppVersionRecord.fetchAll(db) @@ -24,5 +22,4 @@ extension AppVersionRecordStorage { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionStorage.swift index aaa7f24333..9dc62f80e3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/AppVersionStorage.swift @@ -6,11 +6,9 @@ class AppVersionStorage { init(storage: AppVersionRecordStorage) { self.storage = storage } - } extension AppVersionStorage { - var appVersions: [AppVersion] { storage.appVersionRecords.compactMap { AppVersion(version: $0.version, build: $0.build, date: $0.date) @@ -23,5 +21,4 @@ extension AppVersionStorage { } storage.save(appVersionRecords: records) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingRecordStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingRecordStorage.swift index b23bba7807..b1fa78d735 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingRecordStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingRecordStorage.swift @@ -7,11 +7,9 @@ class BlockchainSettingRecordStorage { init(dbPool: DatabasePool) throws { self.dbPool = dbPool } - } extension BlockchainSettingRecordStorage { - func record(blockchainUid: String, key: String) throws -> BlockchainSettingRecord? { try dbPool.read { db in try BlockchainSettingRecord.filter(BlockchainSettingRecord.Columns.blockchainUid == blockchainUid && BlockchainSettingRecord.Columns.key == key).fetchOne(db) @@ -23,5 +21,4 @@ extension BlockchainSettingRecordStorage { try record.insert(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingsStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingsStorage.swift index a128038cbc..54f4372eab 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingsStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/BlockchainSettingsStorage.swift @@ -10,16 +10,14 @@ class BlockchainSettingsStorage { init(storage: BlockchainSettingRecordStorage) { self.storage = storage } - } extension BlockchainSettingsStorage { - func btcRestoreMode(blockchainType: BlockchainType) -> BtcRestoreMode? { try? storage.record(blockchainUid: blockchainType.uid, key: keyBtcRestore) - .flatMap { record in - BtcRestoreMode(rawValue: record.value) - } + .flatMap { record in + BtcRestoreMode(rawValue: record.value) + } } func save(btcRestoreMode: BtcRestoreMode, blockchainType: BlockchainType) { @@ -29,9 +27,9 @@ extension BlockchainSettingsStorage { func btcTransactionSortMode(blockchainType: BlockchainType) -> TransactionDataSortMode? { try? storage.record(blockchainUid: blockchainType.uid, key: keyBtcTransactionSort) - .flatMap { record in - TransactionDataSortMode(rawValue: record.value) - } + .flatMap { record in + TransactionDataSortMode(rawValue: record.value) + } } func save(btcTransactionSortMode: TransactionDataSortMode, blockchainType: BlockchainType) { @@ -40,12 +38,11 @@ extension BlockchainSettingsStorage { } func evmSyncSourceUrl(blockchainType: BlockchainType) -> String? { - try? storage.record(blockchainUid: blockchainType.uid, key: keyEvmSyncSource).flatMap { $0.value } + try? storage.record(blockchainUid: blockchainType.uid, key: keyEvmSyncSource).map(\.value) } func save(evmSyncSourceUrl: String, blockchainType: BlockchainType) { let record = BlockchainSettingRecord(blockchainUid: blockchainType.uid, key: keyEvmSyncSource, value: evmSyncSourceUrl) try? storage.save(record: record) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetManager.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetManager.swift index 095b0c3394..126f5d7e99 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetManager.swift @@ -1,5 +1,5 @@ -import RxSwift import MarketKit +import RxSwift class CexAssetManager { private let accountManager: AccountManager @@ -28,23 +28,21 @@ class CexAssetManager { return records.compactMap { record in CexAsset( - id: record.id, - name: record.name, - freeBalance: record.freeBalance, - lockedBalance: record.lockedBalance, - depositEnabled: record.depositEnabled, - withdrawEnabled: record.withdrawEnabled, - depositNetworks: record.depositNetworks.map { $0.cexDepositNetwork(blockchain: $0.blockchainUid.flatMap { blockchainMap[$0] }) }, - withdrawNetworks: record.withdrawNetworks.map { $0.cexWithdrawNetwork(blockchain: $0.blockchainUid.flatMap { blockchainMap[$0] }) }, - coin: record.coinUid.flatMap { coinMap[$0] } + id: record.id, + name: record.name, + freeBalance: record.freeBalance, + lockedBalance: record.lockedBalance, + depositEnabled: record.depositEnabled, + withdrawEnabled: record.withdrawEnabled, + depositNetworks: record.depositNetworks.map { $0.cexDepositNetwork(blockchain: $0.blockchainUid.flatMap { blockchainMap[$0] }) }, + withdrawNetworks: record.withdrawNetworks.map { $0.cexWithdrawNetwork(blockchain: $0.blockchainUid.flatMap { blockchainMap[$0] }) }, + coin: record.coinUid.flatMap { coinMap[$0] } ) } } - } extension CexAssetManager { - func balanceCexAssets(account: Account) -> [CexAsset] { do { let records = try storage.balanceAssets(accountId: account.id) @@ -72,5 +70,4 @@ extension CexAssetManager { print("Failed to resave: \(error)") } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetRecordStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetRecordStorage.swift index 83cb92c507..dc07812650 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetRecordStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/CexAssetRecordStorage.swift @@ -6,16 +6,14 @@ class CexAssetRecordStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension CexAssetRecordStorage { - func balanceAssets(accountId: String) throws -> [CexAssetRecord] { try dbPool.read { db in try CexAssetRecord - .filter(CexAssetRecord.Columns.accountId == accountId && (CexAssetRecord.Columns.freeBalance != 0 || CexAssetRecord.Columns.lockedBalance != 0)) - .fetchAll(db) + .filter(CexAssetRecord.Columns.accountId == accountId && (CexAssetRecord.Columns.freeBalance != 0 || CexAssetRecord.Columns.lockedBalance != 0)) + .fetchAll(db) } } @@ -40,5 +38,4 @@ extension CexAssetRecordStorage { try CexAssetRecord.filter(CexAssetRecord.Columns.accountId == accountId).deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletCacheStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletCacheStorage.swift index 623cc39427..50af8220ea 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletCacheStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletCacheStorage.swift @@ -6,16 +6,13 @@ class EnabledWalletCacheStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension EnabledWalletCacheStorage { - func enabledWalletCaches(accountId: String) -> [EnabledWalletCache] { try! dbPool.read { db in try EnabledWalletCache.filter(EnabledWalletCache.Columns.accountId == accountId).fetchAll(db) } - } func save(enabledWalletCaches: [EnabledWalletCache]) { @@ -31,5 +28,4 @@ extension EnabledWalletCacheStorage { try EnabledWalletCache.filter(EnabledWalletCache.Columns.accountId == accountId).deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletStorage.swift index 45f033cabe..955c9cbe51 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EnabledWalletStorage.swift @@ -6,11 +6,9 @@ class EnabledWalletStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension EnabledWalletStorage { - func allWallets() throws -> [EnabledWallet] { try dbPool.read { db in try EnabledWallet.fetchAll(db) @@ -38,7 +36,6 @@ extension EnabledWalletStorage { try EnabledWallet.filter(EnabledWallet.Columns.tokenQueryId == enabledWallet.tokenQueryId && EnabledWallet.Columns.accountId == enabledWallet.accountId).deleteAll(db) } } - } func clear() throws { @@ -46,5 +43,4 @@ extension EnabledWalletStorage { try EnabledWallet.deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmAccountRestoreStateStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmAccountRestoreStateStorage.swift index 92c35278cd..ced52f5b4a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmAccountRestoreStateStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmAccountRestoreStateStorage.swift @@ -6,11 +6,9 @@ class EvmAccountRestoreStateStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension EvmAccountRestoreStateStorage { - func evmAccountRestoreState(accountId: String, blockchainUid: String) throws -> EvmAccountRestoreState? { try dbPool.read { db in try EvmAccountRestoreState.filter(EvmAccountRestoreState.Columns.accountId == accountId && EvmAccountRestoreState.Columns.blockchainUid == blockchainUid).fetchOne(db) @@ -22,5 +20,4 @@ extension EvmAccountRestoreStateStorage { try evmAccountRestoreState.insert(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmLabelStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmLabelStorage.swift index 3e34bc8955..87495c20a0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmLabelStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmLabelStorage.swift @@ -6,11 +6,9 @@ class EvmLabelStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension EvmLabelStorage { - func evmMethodLabel(methodId: String) throws -> EvmMethodLabel? { try dbPool.read { db in try EvmMethodLabel.filter(EvmMethodLabel.Columns.methodId == methodId).fetchOne(db) @@ -42,5 +40,4 @@ extension EvmLabelStorage { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmSyncSourceStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmSyncSourceStorage.swift index b6222c4f10..3721798a6f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmSyncSourceStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/EvmSyncSourceStorage.swift @@ -6,12 +6,10 @@ class EvmSyncSourceStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension EvmSyncSourceStorage { - - func getAll() throws -> [EvmSyncSourceRecord] { + func getAll() throws -> [EvmSyncSourceRecord] { try dbPool.read { db in try EvmSyncSourceRecord.fetchAll(db) } @@ -27,7 +25,6 @@ extension EvmSyncSourceStorage { _ = try dbPool.write { db in try record.insert(db) } - } func delete(blockchainTypeUid: String, url: String) throws { @@ -35,5 +32,4 @@ extension EvmSyncSourceStorage { try EvmSyncSourceRecord.filter(EvmSyncSourceRecord.Columns.blockchainTypeUid == blockchainTypeUid && EvmSyncSourceRecord.Columns.url == url).deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/FavoriteCoinRecordStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/FavoriteCoinRecordStorage.swift index 41ca31db8b..bcbd06869e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/FavoriteCoinRecordStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/FavoriteCoinRecordStorage.swift @@ -6,11 +6,9 @@ class FavoriteCoinRecordStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension FavoriteCoinRecordStorage { - var favoriteCoinRecords: [FavoriteCoinRecord] { try! dbPool.read { db in try FavoriteCoinRecord.fetchAll(db) @@ -34,24 +32,23 @@ extension FavoriteCoinRecordStorage { func deleteAll() { _ = try! dbPool.write { db in try FavoriteCoinRecord - .deleteAll(db) + .deleteAll(db) } } func deleteFavoriteCoinRecord(coinUid: String) { _ = try! dbPool.write { db in try FavoriteCoinRecord - .filter(FavoriteCoinRecord.Columns.coinUid == coinUid) - .deleteAll(db) + .filter(FavoriteCoinRecord.Columns.coinUid == coinUid) + .deleteAll(db) } } func favoriteCoinRecordExists(coinUid: String) -> Bool { try! dbPool.read { db in try FavoriteCoinRecord - .filter(FavoriteCoinRecord.Columns.coinUid == coinUid) - .fetchCount(db) > 0 + .filter(FavoriteCoinRecord.Columns.coinUid == coinUid) + .fetchCount(db) > 0 } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/KeychainStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/KeychainStorage.swift index 95361ba18f..0df0708c2d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/KeychainStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/KeychainStorage.swift @@ -17,8 +17,8 @@ extension KeychainStorage { return T(string) } - func set(value: T?, for key: String) throws { - if let value = value { + func set(value: (some LosslessStringConvertible)?, for key: String) throws { + if let value { try keychain.set(value.description, key: key) } else { try keychain.remove(key) @@ -30,7 +30,7 @@ extension KeychainStorage { } func set(value: Data?, for key: String) throws { - if let value = value { + if let value { try keychain.set(value, key: key) } else { try keychain.remove(key) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/LogRecordStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/LogRecordStorage.swift index bdbed91c79..a8601c45b3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/LogRecordStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/LogRecordStorage.swift @@ -6,17 +6,15 @@ class LogRecordStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension LogRecordStorage { - func logs(context: String) -> [LogRecord] { try! dbPool.read { db in try LogRecord - .filter(LogRecord.Columns.context.like("\(context)%")) - .order(LogRecord.Columns.date.asc) - .fetchAll(db) + .filter(LogRecord.Columns.context.like("\(context)%")) + .order(LogRecord.Columns.date.asc) + .fetchAll(db) } } @@ -40,5 +38,4 @@ extension LogRecordStorage { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftDatabaseStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftDatabaseStorage.swift index b42f5f4154..941a18816b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftDatabaseStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftDatabaseStorage.swift @@ -76,44 +76,42 @@ class NftDatabaseStorage { return migrator } - } extension NftDatabaseStorage { - func collections(blockchainTypeUid: String, accountId: String) throws -> [NftCollectionRecord] { try dbPool.read { db in try NftCollectionRecord - .filter(NftCollectionRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftCollectionRecord.Columns.accountId == accountId) - .fetchAll(db) + .filter(NftCollectionRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftCollectionRecord.Columns.accountId == accountId) + .fetchAll(db) } } func assets(blockchainTypeUid: String, accountId: String) throws -> [NftAssetRecord] { try dbPool.read { db in try NftAssetRecord - .filter(NftAssetRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftAssetRecord.Columns.accountId == accountId) - .fetchAll(db) + .filter(NftAssetRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftAssetRecord.Columns.accountId == accountId) + .fetchAll(db) } } func asset(nftUid: NftUid) throws -> NftAssetRecord? { try dbPool.read { db in try NftAssetRecord - .filter(NftAssetRecord.Columns.nftUid == nftUid) - .fetchOne(db) + .filter(NftAssetRecord.Columns.nftUid == nftUid) + .fetchOne(db) } } func save(collections: [NftCollectionRecord], assets: [NftAssetRecord], blockchainTypeUid: String, accountId: String) throws { _ = try dbPool.write { db in try NftCollectionRecord - .filter(NftCollectionRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftCollectionRecord.Columns.accountId == accountId) - .deleteAll(db) + .filter(NftCollectionRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftCollectionRecord.Columns.accountId == accountId) + .deleteAll(db) try NftAssetRecord - .filter(NftAssetRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftAssetRecord.Columns.accountId == accountId) - .deleteAll(db) + .filter(NftAssetRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftAssetRecord.Columns.accountId == accountId) + .deleteAll(db) for collection in collections { try collection.insert(db) @@ -127,8 +125,8 @@ extension NftDatabaseStorage { func metadataSyncRecord(blockchainTypeUid: String, accountId: String) throws -> NftMetadataSyncRecord? { try dbPool.read { db in try NftMetadataSyncRecord - .filter(NftMetadataSyncRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftMetadataSyncRecord.Columns.accountId == accountId) - .fetchOne(db) + .filter(NftMetadataSyncRecord.Columns.blockchainTypeUid == blockchainTypeUid && NftMetadataSyncRecord.Columns.accountId == accountId) + .fetchOne(db) } } @@ -141,8 +139,8 @@ extension NftDatabaseStorage { func assetsBriefMetadata(nftUids: Set) throws -> [NftAssetBriefMetadata] { try dbPool.read { db in try NftAssetBriefMetadata - .filter(nftUids.contains(NftAssetBriefMetadata.Columns.nftUid)) - .fetchAll(db) + .filter(nftUids.contains(NftAssetBriefMetadata.Columns.nftUid)) + .fetchAll(db) } } @@ -153,5 +151,4 @@ extension NftDatabaseStorage { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftStorage.swift index 876d633a58..09c27331d8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/NftStorage.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import MarketKit +import RxSwift class NftStorage { private let marketKit: MarketKit.Kit @@ -12,11 +12,11 @@ class NftStorage { } private func tokenQueries(records: [NftPriceRecord]) -> [TokenQuery] { - Array(Set(records.map { $0.tokenQuery })) + Array(Set(records.map(\.tokenQuery))) } private func nftPrice(record: NftPriceRecord?, tokens: [Token]) -> NftPrice? { - guard let record = record else { + guard let record else { return nil } @@ -29,37 +29,35 @@ class NftStorage { private func asset(record: NftAssetRecord, tokens: [Token]) -> NftAssetShortMetadata { NftAssetShortMetadata( - nftUid: record.nftUid, - providerCollectionUid: record.providerCollectionUid, - name: record.name, - previewImageUrl: record.previewImageUrl, - onSale: record.onSale, - lastSalePrice: nftPrice(record: record.lastSalePrice, tokens: tokens) + nftUid: record.nftUid, + providerCollectionUid: record.providerCollectionUid, + name: record.name, + previewImageUrl: record.previewImageUrl, + onSale: record.onSale, + lastSalePrice: nftPrice(record: record.lastSalePrice, tokens: tokens) ) } private func collection(record: NftCollectionRecord, tokens: [Token]) -> NftCollectionShortMetadata { NftCollectionShortMetadata( - providerUid: record.providerUid, - name: record.name, - thumbnailImageUrl: record.thumbnailImageUrl, - averagePrice7d: nftPrice(record: record.averagePrice7d, tokens: tokens), - averagePrice30d: nftPrice(record: record.averagePrice30d, tokens: tokens) + providerUid: record.providerUid, + name: record.name, + thumbnailImageUrl: record.thumbnailImageUrl, + averagePrice7d: nftPrice(record: record.averagePrice7d, tokens: tokens), + averagePrice30d: nftPrice(record: record.averagePrice30d, tokens: tokens) ) } private func priceRecords(collectionRecords: [NftCollectionRecord]) -> [NftPriceRecord] { - collectionRecords.compactMap { $0.averagePrice7d } + collectionRecords.compactMap { $0.averagePrice30d } + collectionRecords.compactMap(\.averagePrice7d) + collectionRecords.compactMap(\.averagePrice30d) } private func priceRecords(assetRecords: [NftAssetRecord]) -> [NftPriceRecord] { - assetRecords.compactMap { $0.lastSalePrice } + assetRecords.compactMap(\.lastSalePrice) } - } extension NftStorage { - func addressMetadata(nftKey: NftKey) -> NftAddressMetadata? { do { let collectionRecords = try storage.collections(blockchainTypeUid: nftKey.blockchainType.uid, accountId: nftKey.account.id) @@ -69,8 +67,8 @@ extension NftStorage { let tokens = try marketKit.tokens(queries: tokenQueries(records: priceRecords)) return NftAddressMetadata( - collections: collectionRecords.map { collection(record: $0, tokens: tokens) }, - assets: assetRecords.map { asset(record: $0, tokens: tokens) } + collections: collectionRecords.map { collection(record: $0, tokens: tokens) }, + assets: assetRecords.map { asset(record: $0, tokens: tokens) } ) } catch { print("Could not fetch NftAddressMetadata: \(error)") @@ -94,10 +92,10 @@ extension NftStorage { func save(addressMetadata: NftAddressMetadata, nftKey: NftKey) { do { try storage.save( - collections: addressMetadata.collections.map { NftCollectionRecord(blockchainTypeUid: nftKey.blockchainType.uid, accountId: nftKey.account.id, collection: $0) }, - assets: addressMetadata.assets.map { NftAssetRecord(blockchainTypeUid: nftKey.blockchainType.uid, accountId: nftKey.account.id, asset: $0) }, - blockchainTypeUid: nftKey.blockchainType.uid, - accountId: nftKey.account.id + collections: addressMetadata.collections.map { NftCollectionRecord(blockchainTypeUid: nftKey.blockchainType.uid, accountId: nftKey.account.id, collection: $0) }, + assets: addressMetadata.assets.map { NftAssetRecord(blockchainTypeUid: nftKey.blockchainType.uid, accountId: nftKey.account.id, asset: $0) }, + blockchainTypeUid: nftKey.blockchainType.uid, + accountId: nftKey.account.id ) } catch { print("Could not save NftAddressMetadata: \(error)") @@ -138,5 +136,4 @@ extension NftStorage { print("Could not save [NftAssetBriefMetadata]: \(error)") } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/RestoreSettingsStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/RestoreSettingsStorage.swift index 0b30ef3716..2f3a45f55d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/RestoreSettingsStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/RestoreSettingsStorage.swift @@ -6,11 +6,9 @@ class RestoreSettingsStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension RestoreSettingsStorage { - func restoreSettings(accountId: String, blockchainUid: String) -> [RestoreSettingRecord] { try! dbPool.read { db in try RestoreSettingRecord.filter(RestoreSettingRecord.Columns.accountId == accountId && RestoreSettingRecord.Columns.blockchainUid == blockchainUid).fetchAll(db) @@ -36,5 +34,4 @@ extension RestoreSettingsStorage { try RestoreSettingRecord.filter(RestoreSettingRecord.Columns.accountId == accountId).deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/SharedLocalStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/SharedLocalStorage.swift index 4ac189a938..46ccbbfae0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/SharedLocalStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/SharedLocalStorage.swift @@ -5,12 +5,12 @@ struct SharedLocalStorage { userDefaults?.value(forKey: key) as? T } - func set(value: T?, for key: String) { + func set(value: (some Any)?, for key: String) { guard let userDefaults else { return } - if let value = value { + if let value { userDefaults.set(value, forKey: key) } else { userDefaults.removeObject(forKey: key) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/StorageMigrator.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/StorageMigrator.swift index 58cadd6cfa..72d9feca9d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/StorageMigrator.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/StorageMigrator.swift @@ -1,13 +1,12 @@ import Foundation -import RxSwift -import RxCocoa import GRDB -import KeychainAccess import HsToolKit +import KeychainAccess import MarketKit +import RxCocoa +import RxSwift class StorageMigrator { - static func migrate(dbPool: DatabasePool) throws { var migrator = DatabaseMigrator() @@ -25,7 +24,7 @@ class StorageMigrator { t.column(AccountRecord_v_0_10.Columns.eosAccount.name, .text) t.primaryKey([ - AccountRecord_v_0_10.Columns.id.name + AccountRecord_v_0_10.Columns.id.name, ], onConflict: .replace) } } @@ -71,9 +70,9 @@ class StorageMigrator { let accountId = accountRecord.id try db.execute(sql: """ - INSERT INTO \(EnabledWallet_v_0_10.databaseTableName)(`coinCode`, `\(EnabledWallet_v_0_10.Columns.accountId.name)`, `\(EnabledWallet_v_0_10.Columns.syncMode.name)`, `\(EnabledWallet_v_0_10.Columns.walletOrder.name)`) - SELECT `coinCode`, '\(accountId)', '\(syncMode)', `coinOrder` FROM enabled_coins - """) + INSERT INTO \(EnabledWallet_v_0_10.databaseTableName)(`coinCode`, `\(EnabledWallet_v_0_10.Columns.accountId.name)`, `\(EnabledWallet_v_0_10.Columns.syncMode.name)`, `\(EnabledWallet_v_0_10.Columns.walletOrder.name)`) + SELECT `coinCode`, '\(accountId)', '\(syncMode)', `coinOrder` FROM enabled_coins + """) try db.drop(table: "enabled_coins") } @@ -90,9 +89,9 @@ class StorageMigrator { } try db.execute(sql: """ - INSERT INTO \(tempTableName)(`\(EnabledWallet_v_0_10.Columns.coinId.name)`, `\(EnabledWallet_v_0_10.Columns.accountId.name)`, `\(EnabledWallet_v_0_10.Columns.syncMode.name)`, `\(EnabledWallet_v_0_10.Columns.walletOrder.name)`) - SELECT `coinCode`, `accountId`, `syncMode`, `walletOrder` FROM \(EnabledWallet_v_0_10.databaseTableName) - """) + INSERT INTO \(tempTableName)(`\(EnabledWallet_v_0_10.Columns.coinId.name)`, `\(EnabledWallet_v_0_10.Columns.accountId.name)`, `\(EnabledWallet_v_0_10.Columns.syncMode.name)`, `\(EnabledWallet_v_0_10.Columns.walletOrder.name)`) + SELECT `coinCode`, `accountId`, `syncMode`, `walletOrder` FROM \(EnabledWallet_v_0_10.databaseTableName) + """) try db.drop(table: EnabledWallet_v_0_10.databaseTableName) try db.rename(table: tempTableName, to: EnabledWallet_v_0_10.databaseTableName) @@ -124,16 +123,16 @@ class StorageMigrator { let origin = oldAccount.defaultSyncMode == "new" ? "created" : "restored" let newAccount = AccountRecord_v_0_19( - id: oldAccount.id, - name: oldAccount.name, - type: oldAccount.type, - origin: origin, - backedUp: oldAccount.backedUp, - wordsKey: oldAccount.wordsKey, - saltKey: oldAccount.saltKey, - birthdayHeightKey: nil, - dataKey: oldAccount.dataKey, - eosAccount: oldAccount.eosAccount + id: oldAccount.id, + name: oldAccount.name, + type: oldAccount.type, + origin: origin, + backedUp: oldAccount.backedUp, + wordsKey: oldAccount.wordsKey, + saltKey: oldAccount.saltKey, + birthdayHeightKey: nil, + dataKey: oldAccount.dataKey, + eosAccount: oldAccount.eosAccount ) try newAccount.insert(db) @@ -161,19 +160,19 @@ class StorageMigrator { var derivation: String? var syncMode: String? - if let oldDerivation = oldDerivation, oldWallet.coinId == "BTC" { + if let oldDerivation, oldWallet.coinId == "BTC" { derivation = oldDerivation } - if let oldSyncMode = oldSyncMode, (oldWallet.coinId == "BTC" || oldWallet.coinId == "BCH" || oldWallet.coinId == "DASH") { + if let oldSyncMode, oldWallet.coinId == "BTC" || oldWallet.coinId == "BCH" || oldWallet.coinId == "DASH" { syncMode = oldSyncMode } let newWallet = EnabledWallet_v_0_13( - coinId: oldWallet.coinId, - accountId: oldWallet.accountId, - derivation: derivation, - syncMode: syncMode + coinId: oldWallet.coinId, + accountId: oldWallet.accountId, + derivation: derivation, + syncMode: syncMode ) try newWallet.insert(db) @@ -186,10 +185,10 @@ class StorageMigrator { } let newWallet = EnabledWallet_v_0_13( - coinId: "SAI", - accountId: wallet.accountId, - derivation: wallet.derivation, - syncMode: wallet.syncMode + coinId: "SAI", + accountId: wallet.accountId, + derivation: wallet.derivation, + syncMode: wallet.syncMode ) try wallet.delete(db) @@ -208,22 +207,22 @@ class StorageMigrator { migrator.registerMigration("fillBlockchainSettingsFromEnabledWallets") { db in let wallets = try EnabledWallet_v_0_13.filter(EnabledWallet_v_0_13.Columns.coinId == "BTC" || - EnabledWallet_v_0_13.Columns.coinId == "LTC" || - EnabledWallet_v_0_13.Columns.coinId == "BCH" || - EnabledWallet_v_0_13.Columns.coinId == "DASH").fetchAll(db) + EnabledWallet_v_0_13.Columns.coinId == "LTC" || + EnabledWallet_v_0_13.Columns.coinId == "BCH" || + EnabledWallet_v_0_13.Columns.coinId == "DASH").fetchAll(db) let coinTypeKeyMap = [ "BTC": "bitcoin", "LTC": "litecoin", "BCH": "bitcoinCash", - "DASH": "dash" + "DASH": "dash", ] let derivationSettings: [BlockchainSettingRecord_v_0_24] = wallets.compactMap { wallet in guard - let coinTypeKey = coinTypeKeyMap[wallet.coinId], - let derivation = wallet.derivation - else { + let coinTypeKey = coinTypeKeyMap[wallet.coinId], + let derivation = wallet.derivation + else { return nil } @@ -231,9 +230,9 @@ class StorageMigrator { } let syncSettings: [BlockchainSettingRecord_v_0_24] = wallets.compactMap { wallet in guard - let coinTypeKey = coinTypeKeyMap[wallet.coinId], - let syncMode = wallet.syncMode - else { + let coinTypeKey = coinTypeKeyMap[wallet.coinId], + let syncMode = wallet.syncMode + else { return nil } @@ -312,15 +311,15 @@ class StorageMigrator { } let newAccount = AccountRecord_v_0_20( - id: oldAccount.id, - name: oldAccount.name, - type: oldAccount.type, - origin: oldAccount.origin, - backedUp: oldAccount.backedUp, - wordsKey: oldAccount.wordsKey, - saltKey: oldAccount.saltKey, - birthdayHeightKey: oldAccount.birthdayHeightKey, - dataKey: oldAccount.dataKey + id: oldAccount.id, + name: oldAccount.name, + type: oldAccount.type, + origin: oldAccount.origin, + backedUp: oldAccount.backedUp, + wordsKey: oldAccount.wordsKey, + saltKey: oldAccount.saltKey, + birthdayHeightKey: oldAccount.birthdayHeightKey, + dataKey: oldAccount.dataKey ) try newAccount.insert(db) @@ -403,15 +402,15 @@ class StorageMigrator { } let newAccount = AccountRecord_v_0_36( - id: oldAccount.id, - name: "Wallet \(index + 1)", - type: accountType, - origin: oldAccount.origin, - backedUp: oldAccount.backedUp, - wordsKey: oldAccount.wordsKey, - saltKey: oldAccount.saltKey, - dataKey: oldAccount.dataKey, - bip39Compliant: nil + id: oldAccount.id, + name: "Wallet \(index + 1)", + type: accountType, + origin: oldAccount.origin, + backedUp: oldAccount.backedUp, + wordsKey: oldAccount.wordsKey, + saltKey: oldAccount.saltKey, + dataKey: oldAccount.dataKey, + bip39Compliant: nil ) try newAccount.insert(db) @@ -451,9 +450,9 @@ class StorageMigrator { } let newWallet = EnabledWallet_v_0_25( - coinId: oldWallet.coinId, - coinSettingsId: coinSettingsId, - accountId: oldWallet.accountId + coinId: oldWallet.coinId, + coinSettingsId: coinSettingsId, + accountId: oldWallet.accountId ) try newWallet.insert(db) @@ -568,12 +567,12 @@ class StorageMigrator { for customToken in customTokens { if let enabledWallet = try EnabledWallet_v_0_25.filter(EnabledWallet_v_0_25.Columns.coinId == customToken.coinTypeId).fetchOne(db) { let newEnabledWallet = EnabledWallet_v_0_25( - coinId: enabledWallet.coinId, - coinSettingsId: enabledWallet.coinSettingsId, - accountId: enabledWallet.accountId, - coinName: customToken.coinName, - coinCode: customToken.coinCode, - coinDecimals: customToken.decimals + coinId: enabledWallet.coinId, + coinSettingsId: enabledWallet.coinSettingsId, + accountId: enabledWallet.accountId, + coinName: customToken.coinName, + coinCode: customToken.coinCode, + coinDecimals: customToken.decimals ) try newEnabledWallet.insert(db) @@ -621,10 +620,10 @@ class StorageMigrator { for old in oldRestoreSettings { let record = RestoreSettingRecord( - accountId: old.accountId, - blockchainUid: old.coinId, // old setting used coin type id and for Zcash only. Blockchain uid and coin type id for Zcash is the same - key: old.key, - value: old.value + accountId: old.accountId, + blockchainUid: old.coinId, // old setting used coin type id and for Zcash only. Blockchain uid and coin type id for Zcash is the same + key: old.key, + value: old.value ) try record.insert(db) @@ -633,12 +632,12 @@ class StorageMigrator { // BlockchainSettingRecord try BlockchainSettingRecord - .filter(BlockchainSettingRecord.Columns.blockchainUid == "bitcoinCash") - .updateAll(db, BlockchainSettingRecord.Columns.blockchainUid.set(to: "bitcoin-cash")) + .filter(BlockchainSettingRecord.Columns.blockchainUid == "bitcoinCash") + .updateAll(db, BlockchainSettingRecord.Columns.blockchainUid.set(to: "bitcoin-cash")) try BlockchainSettingRecord - .filter(BlockchainSettingRecord.Columns.blockchainUid == "binanceSmartChain") - .updateAll(db, BlockchainSettingRecord.Columns.blockchainUid.set(to: "binance-smart-chain")) + .filter(BlockchainSettingRecord.Columns.blockchainUid == "binanceSmartChain") + .updateAll(db, BlockchainSettingRecord.Columns.blockchainUid.set(to: "binance-smart-chain")) // EnabledWallet @@ -659,12 +658,12 @@ class StorageMigrator { for old in oldWallets { let record = EnabledWallet_v_0_34( - tokenQueryId: tokenQuery(coinTypeId: old.coinId).id, - coinSettingsId: old.coinSettingsId, - accountId: old.accountId, - coinName: old.coinName, - coinCode: old.coinCode, - tokenDecimals: old.coinDecimals + tokenQueryId: tokenQuery(coinTypeId: old.coinId).id, + coinSettingsId: old.coinSettingsId, + accountId: old.accountId, + coinName: old.coinName, + coinCode: old.coinCode, + tokenDecimals: old.coinDecimals ) try record.insert(db) @@ -826,12 +825,12 @@ class StorageMigrator { case .polygon: return TokenQuery(blockchainType: .polygon, tokenType: .native) case .ethereumOptimism: return TokenQuery(blockchainType: .optimism, tokenType: .native) case .ethereumArbitrumOne: return TokenQuery(blockchainType: .arbitrumOne, tokenType: .native) - case .erc20(let address): return TokenQuery(blockchainType: .ethereum, tokenType: .eip20(address: address)) - case .bep20(let address): return TokenQuery(blockchainType: .binanceSmartChain, tokenType: .eip20(address: address)) - case .mrc20(let address): return TokenQuery(blockchainType: .polygon, tokenType: .eip20(address: address)) - case .optimismErc20(let address): return TokenQuery(blockchainType: .optimism, tokenType: .eip20(address: address)) - case .arbitrumOneErc20(let address): return TokenQuery(blockchainType: .arbitrumOne, tokenType: .eip20(address: address)) - case .bep2(let symbol): return symbol == "BNB" ? TokenQuery(blockchainType: .binanceChain, tokenType: .native) : TokenQuery(blockchainType: .binanceChain, tokenType: .bep2(symbol: symbol)) + case let .erc20(address): return TokenQuery(blockchainType: .ethereum, tokenType: .eip20(address: address)) + case let .bep20(address): return TokenQuery(blockchainType: .binanceSmartChain, tokenType: .eip20(address: address)) + case let .mrc20(address): return TokenQuery(blockchainType: .polygon, tokenType: .eip20(address: address)) + case let .optimismErc20(address): return TokenQuery(blockchainType: .optimism, tokenType: .eip20(address: address)) + case let .arbitrumOneErc20(address): return TokenQuery(blockchainType: .arbitrumOne, tokenType: .eip20(address: address)) + case let .bep2(symbol): return symbol == "BNB" ? TokenQuery(blockchainType: .binanceChain, tokenType: .native) : TokenQuery(blockchainType: .binanceChain, tokenType: .bep2(symbol: symbol)) default: return TokenQuery(blockchainType: .unsupported(uid: ""), tokenType: .unsupported(type: "", reference: nil)) } } @@ -847,55 +846,53 @@ class StorageMigrator { let tokenType = chunks[1] let tokenTypeChunks = tokenType.split(separator: ":").map { String($0) } - guard tokenTypeChunks.count == 1 && tokenTypeChunks[0] == "native" else { + guard tokenTypeChunks.count == 1, tokenTypeChunks[0] == "native" else { return tokenQueryId } switch blockchainUid { - case "bitcoin", "litecoin": - let chunks = coinSettingsId.split(separator: "|") - - for chunk in chunks { - let subChunks = chunk.split(separator: ":") - - guard subChunks.count == 2 else { - continue - } + case "bitcoin", "litecoin": + let chunks = coinSettingsId.split(separator: "|") - let settingsName = String(subChunks[0]) - let derivation = String(subChunks[1]) - guard settingsName == "derivation", ["bip44", "bip49", "bip84", "bip86"].contains(derivation) else { - continue - } + for chunk in chunks { + let subChunks = chunk.split(separator: ":") - return "\(blockchainUid)|derived:\(derivation)" + guard subChunks.count == 2 else { + continue } + let settingsName = String(subChunks[0]) + let derivation = String(subChunks[1]) + guard settingsName == "derivation", ["bip44", "bip49", "bip84", "bip86"].contains(derivation) else { + continue + } - case "bitcoin-cash": - let chunks = coinSettingsId.split(separator: "|") + return "\(blockchainUid)|derived:\(derivation)" + } - for chunk in chunks { - let subChunks = chunk.split(separator: ":") + case "bitcoin-cash": + let chunks = coinSettingsId.split(separator: "|") - guard subChunks.count == 2 else { - continue - } + for chunk in chunks { + let subChunks = chunk.split(separator: ":") - let settingsName = String(subChunks[0]) - let addressType = String(subChunks[1]) - guard settingsName == "bitcoinCashCoinType", ["type0", "type145"].contains(addressType) else { - continue - } + guard subChunks.count == 2 else { + continue + } - return "\(blockchainUid)|address_type:\(addressType)" + let settingsName = String(subChunks[0]) + let addressType = String(subChunks[1]) + guard settingsName == "bitcoinCashCoinType", ["type0", "type145"].contains(addressType) else { + continue } - default: - return tokenQueryId + return "\(blockchainUid)|address_type:\(addressType)" + } + + default: + return tokenQueryId } return nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/SyncerStateStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/SyncerStateStorage.swift index fc22154e73..8826dd6ded 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/SyncerStateStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/SyncerStateStorage.swift @@ -6,11 +6,9 @@ class SyncerStateStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension SyncerStateStorage { - func value(key: String) throws -> String? { try dbPool.read { db in try SyncerState.filter(SyncerState.Columns.key == key).fetchOne(db)?.value @@ -29,5 +27,4 @@ extension SyncerStateStorage { try SyncerState.filter(SyncerState.Columns.key == key).deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/UserDefaultsStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/UserDefaultsStorage.swift index e17dd9661d..2003e54ece 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/UserDefaultsStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/UserDefaultsStorage.swift @@ -5,8 +5,8 @@ class UserDefaultsStorage { UserDefaults.standard.value(forKey: key) as? T } - func set(value: T?, for key: String) { - if let value = value { + func set(value: (some Any)?, for key: String) { + if let value { UserDefaults.standard.set(value, forKey: key) } else { UserDefaults.standard.removeObject(forKey: key) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletConnectSessionStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletConnectSessionStorage.swift index 8c41e1f696..100ba7da9a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletConnectSessionStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletConnectSessionStorage.swift @@ -6,15 +6,13 @@ class WalletConnectSessionStorage { init(dbPool: DatabasePool) { self.dbPool = dbPool } - } extension WalletConnectSessionStorage { - func sessions(accountId: String?) -> [WalletConnectSession] { try! dbPool.read { db in var request = WalletConnectSession.all() - if let accountId = accountId { + if let accountId { request = request.filter(WalletConnectSession.Columns.accountId == accountId) } return try request.fetchAll(db) @@ -42,5 +40,4 @@ extension WalletConnectSessionStorage { try WalletConnectSession.filter(WalletConnectSession.Columns.accountId == accountId).deleteAll(db) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletStorage.swift index 83799680b7..d9c20b6f0a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/WalletStorage.swift @@ -1,5 +1,5 @@ -import RxSwift import MarketKit +import RxSwift class WalletStorage { private let marketKit: MarketKit.Kit @@ -12,25 +12,23 @@ class WalletStorage { private func enabledWallet(wallet: Wallet) -> EnabledWallet { EnabledWallet( - tokenQueryId: wallet.token.tokenQuery.id, - accountId: wallet.account.id, - coinName: wallet.coin.name, - coinCode: wallet.coin.code, - tokenDecimals: wallet.token.decimals + tokenQueryId: wallet.token.tokenQuery.id, + accountId: wallet.account.id, + coinName: wallet.coin.name, + coinCode: wallet.coin.code, + tokenDecimals: wallet.token.decimals ) } - } extension WalletStorage { - func wallets(account: Account) throws -> [Wallet] { let enabledWallets = try storage.enabledWallets(accountId: account.id) let queries = enabledWallets.compactMap { TokenQuery(id: $0.tokenQueryId) } let tokens = try marketKit.tokens(queries: queries) - let blockchainUids = queries.map { $0.blockchainType.uid } + let blockchainUids = queries.map(\.blockchainType.uid) let blockchains = try marketKit.blockchains(uids: blockchainUids) return enabledWallets.compactMap { enabledWallet in @@ -43,14 +41,15 @@ extension WalletStorage { } if let coinName = enabledWallet.coinName, let coinCode = enabledWallet.coinCode, let tokenDecimals = enabledWallet.tokenDecimals, - let blockchain = blockchains.first(where: { $0.uid == tokenQuery.blockchainType.uid }) { + let blockchain = blockchains.first(where: { $0.uid == tokenQuery.blockchainType.uid }) + { let coinUid = tokenQuery.customCoinUid let token = Token( - coin: Coin(uid: coinUid, name: coinName, code: coinCode), - blockchain: blockchain, - type: tokenQuery.tokenType, - decimals: tokenDecimals + coin: Coin(uid: coinUid, name: coinName, code: coinCode), + blockchain: blockchain, + type: tokenQuery.tokenType, + decimals: tokenDecimals ) return Wallet(token: token, account: account) @@ -73,5 +72,4 @@ extension WalletStorage { func clearWallets() { try? storage.clear() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/Auditor.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/Auditor.swift index 5cf3278c91..8514d8258e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/Auditor.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/Auditor.swift @@ -1,11 +1,9 @@ -import UIKit import MarketKit +import UIKit extension Auditor { - var logoUrl: String? { let scale = Int(UIScreen.main.scale) return "https://cdn.blocksdecoded.com/auditor-icons/\(name)@\(scale)x.png".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/Blockchain.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/Blockchain.swift index 00e713af14..83c467d36c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/Blockchain.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/Blockchain.swift @@ -10,7 +10,7 @@ extension Blockchain { func explorerUrl(reference: String?) -> String? { // using eip3091url field as it was renamed in MarketKit for further refactoring - guard let explorerUrl = explorerUrl, let reference = reference else { + guard let explorerUrl, let reference else { return nil } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/Coin.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/Coin.swift index 9eec84bdb9..e7881e63b4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/Coin.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/Coin.swift @@ -1,11 +1,9 @@ -import UIKit import MarketKit +import UIKit extension Coin { - var imageUrl: String { let scale = Int(UIScreen.main.scale) return "https://cdn.blocksdecoded.com/coin-icons/32px/\(uid)@\(scale)x.png" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/CoinCategory.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/CoinCategory.swift index 2bf169c476..91109ee578 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/CoinCategory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/CoinCategory.swift @@ -1,11 +1,9 @@ -import UIKit import MarketKit +import UIKit extension CoinCategory { - var imageUrl: String { let scale = Int(UIScreen.main.scale) return "https://cdn.blocksdecoded.com/category-icons/\(uid)@\(scale)x.png" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/CoinInvestment.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/CoinInvestment.swift index 6de6592348..d0793a3351 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/CoinInvestment.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/CoinInvestment.swift @@ -1,11 +1,9 @@ -import UIKit import MarketKit +import UIKit extension CoinInvestment.Fund { - var logoUrl: String { let scale = Int(UIScreen.main.scale) return "https://cdn.blocksdecoded.com/fund-icons/\(uid)@\(scale)x.png" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/CoinTreasury.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/CoinTreasury.swift index c3a87d818c..b8684c2b4e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/CoinTreasury.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/CoinTreasury.swift @@ -1,11 +1,9 @@ -import UIKit import MarketKit +import UIKit extension CoinTreasury { - var fundLogoUrl: String { let scale = Int(UIScreen.main.scale) return "https://cdn.blocksdecoded.com/treasury-icons/\(fundUid)@\(scale)x.png" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/Encodable.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/Encodable.swift index 0ccefe8edb..a4e70c6136 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/Encodable.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/Encodable.swift @@ -1,12 +1,13 @@ import Foundation -extension Encodable { - public var encoded: Data { +public extension Encodable { + var encoded: Data { let encoder = JSONEncoder() encoder.outputFormatting = [.sortedKeys] return try! encoder.encode(self) } - public var encodedString: String { + + var encodedString: String { String(data: encoded, encoding: .utf8)! } } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/FileManager.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/FileManager.swift index 9e8b1897d6..89dacc4af8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/FileManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/FileManager.swift @@ -1,10 +1,9 @@ import Foundation extension FileManager { - func fileExists(coordinatingAccessAt fileURL: URL) throws -> (exists: Bool, isDirectory: Bool) { var isDir: ObjCBool = false - var exists: Bool = false + var exists = false try coordinate(readingItemAt: fileURL) { url in exists = fileExists(atPath: url.path, isDirectory: &isDir) } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/FullCoin.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/FullCoin.swift index e88fcfd3b3..3026cf2f88 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/FullCoin.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/FullCoin.swift @@ -1,7 +1,7 @@ import MarketKit extension FullCoin: Equatable { - public static func ==(lhs: Self, rhs: Self) -> Bool { + public static func == (lhs: Self, rhs: Self) -> Bool { lhs.coin == rhs.coin && lhs.tokens == rhs.tokens } } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/Kmm.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/Kmm.swift index d7001abb45..a6b5273ca4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/Kmm.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/Kmm.swift @@ -48,7 +48,7 @@ extension Publishers { subscriber.receive(subscription: subscription) let cancellable = onCollect({ input in _ = subscriber.receive(input) }) { failure in - if let failure = failure { + if let failure { subscriber.receive(completion: .failure(failure)) } else { subscriber.receive(completion: .finished) @@ -96,7 +96,7 @@ extension Publisher { You can hook into these failures by assigning a function to `PublisherHooks.willCompleteOnFailure`. */ func completeOnFailure(file: String = #file, fileID: String = #fileID, filePath: String = #filePath, line: Int = #line, column: Int = #column, function: String = #function, dsoHandle: UnsafeRawPointer = #dsohandle) -> Publishers.Catch> { - return `catch` { error in + `catch` { error in let callsite = Callsite(file: file, fileID: fileID, filePath: filePath, line: line, column: column, function: function, dsoHandle: dsoHandle) PublisherFailures.willCompleteOnFailure(error, callsite) return Empty(completeImmediately: true) diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/Misc.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/Misc.swift index 1c039d66c6..2b389e49d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/Misc.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/Misc.swift @@ -1,10 +1,8 @@ import UIKit extension String { - var headerImageUrl: String { let scale = Int(UIScreen.main.scale) return "https://cdn.blocksdecoded.com/header-images/\(self)@\(scale)x.png" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/Token.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/Token.swift index 5d537d58a5..41f2cdd5f5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/Token.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/Token.swift @@ -1,7 +1,6 @@ import MarketKit extension Token { - var protocolName: String? { switch type { case .native: @@ -48,17 +47,15 @@ extension Token { var badge: String? { switch type { - case .derived(let derivation): return derivation.mnemonicDerivation.rawValue.uppercased() - case .addressType(let type): return type.bitcoinCashCoinType.title.uppercased() + case let .derived(derivation): return derivation.mnemonicDerivation.rawValue.uppercased() + case let .addressType(type): return type.bitcoinCashCoinType.title.uppercased() default: return protocolName?.uppercased() } } - } extension Token: Comparable { - - public static func <(lhs: Token, rhs: Token) -> Bool { + public static func < (lhs: Token, rhs: Token) -> Bool { let lhsTypeOrder = lhs.type.order let rhsTypeOrder = rhs.type.order @@ -68,5 +65,4 @@ extension Token: Comparable { return lhs.blockchainType.order < rhs.blockchainType.order } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/TokenQuery.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/TokenQuery.swift index 863b6ba96d..c4b94e426f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/TokenQuery.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/TokenQuery.swift @@ -1,9 +1,7 @@ import MarketKit extension TokenQuery { - var customCoinUid: String { "custom-\(id)" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/TokenType.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/TokenType.swift index 5a041bc93a..0cacf7c5de 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/TokenType.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/TokenType.swift @@ -1,7 +1,6 @@ import MarketKit extension TokenType { - var isNative: Bool { switch self { case .native, .derived, .addressType: return true @@ -23,7 +22,7 @@ extension TokenType { var bep2Symbol: String? { switch self { - case .bep2(let symbol): return symbol + case let .bep2(symbol): return symbol default: return nil } } @@ -31,57 +30,56 @@ extension TokenType { var order: Int { switch self { case .native: return 0 - case .derived(let derivation): return derivation.mnemonicDerivation.order - case .addressType(let type): return type.bitcoinCashCoinType.order + case let .derived(derivation): return derivation.mnemonicDerivation.order + case let .addressType(type): return type.bitcoinCashCoinType.order default: return Int.max } } var derivation: MnemonicDerivation? { switch self { - case .derived(let derivation): return derivation.mnemonicDerivation + case let .derived(derivation): return derivation.mnemonicDerivation default: return nil } } var bitcoinCashCoinType: BitcoinCashCoinType? { switch self { - case .addressType(let type): return type.bitcoinCashCoinType + case let .addressType(type): return type.bitcoinCashCoinType default: return nil } } var title: String { switch self { - case .derived(let derivation): return derivation.mnemonicDerivation.title - case .addressType(let type): return type.bitcoinCashCoinType.title + case let .derived(derivation): return derivation.mnemonicDerivation.title + case let .addressType(type): return type.bitcoinCashCoinType.title default: return "" } } var description: String { switch self { - case .derived(let derivation): return derivation.mnemonicDerivation.addressType + derivation.mnemonicDerivation.recommended - case .addressType(let type): return type.bitcoinCashCoinType.description + type.bitcoinCashCoinType.recommended + case let .derived(derivation): return derivation.mnemonicDerivation.addressType + derivation.mnemonicDerivation.recommended + case let .addressType(type): return type.bitcoinCashCoinType.description + type.bitcoinCashCoinType.recommended default: return "" } } var isDefault: Bool { switch self { - case .derived(let derivation): return derivation.mnemonicDerivation == MnemonicDerivation.default - case .addressType(let type): return type.bitcoinCashCoinType == BitcoinCashCoinType.default + case let .derived(derivation): return derivation.mnemonicDerivation == MnemonicDerivation.default + case let .addressType(type): return type.bitcoinCashCoinType == BitcoinCashCoinType.default default: return false } } var meta: String? { switch self { - case .derived(let derivation): return derivation.rawValue - case .addressType(let type): return type.rawValue - case .bep2(let symbol): return symbol + case let .derived(derivation): return derivation.rawValue + case let .addressType(type): return type.rawValue + case let .bep2(symbol): return symbol default: return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AccountRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/AccountRecord.swift index 8a4ca6dcb5..c4c67bc69d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AccountRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AccountRecord.swift @@ -66,5 +66,4 @@ class AccountRecord: Record { container[Columns.dataKey] = dataKey container[Columns.bip39Compliant] = bip39Compliant } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/ActiveAccount.swift b/UnstoppableWallet/UnstoppableWallet/Models/ActiveAccount.swift index 8f6619507e..d24e7c9045 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/ActiveAccount.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/ActiveAccount.swift @@ -30,5 +30,4 @@ class ActiveAccount: Record { container[Columns.level] = level container[Columns.accountId] = accountId } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AdapterState.swift b/UnstoppableWallet/UnstoppableWallet/Models/AdapterState.swift index f05ae385c0..57f2b7dfde 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AdapterState.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AdapterState.swift @@ -28,15 +28,14 @@ enum AdapterState { case .stopped, .notSynced: return false } } - } extension AdapterState: Equatable { - public static func ==(lhs: AdapterState, rhs: AdapterState) -> Bool { + public static func == (lhs: AdapterState, rhs: AdapterState) -> Bool { switch (lhs, rhs) { case (.synced, .synced): return true - case (.syncing(let lProgress, let lLastBlockDate), .syncing(let rProgress, let rLastBlockDate)): return lProgress == rProgress && lLastBlockDate == rLastBlockDate - case (.customSyncing(let lMain, let lSecondary, let lProgress), .customSyncing(let rMain, let rSecondary, let rProgress)): return lMain == rMain && lSecondary == rSecondary && lProgress == rProgress + case let (.syncing(lProgress, lLastBlockDate), .syncing(rProgress, rLastBlockDate)): return lProgress == rProgress && lLastBlockDate == rLastBlockDate + case let (.customSyncing(lMain, lSecondary, lProgress), .customSyncing(rMain, rSecondary, rProgress)): return lMain == rMain && lSecondary == rSecondary && lProgress == rProgress case (.notSynced, .notSynced): return true case (.stopped, .stopped): return true default: return false diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Address.swift b/UnstoppableWallet/UnstoppableWallet/Models/Address.swift index 6e7dba5a6a..f9f3cd420b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Address.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Address.swift @@ -11,9 +11,8 @@ struct Address: Equatable { domain ?? raw } - static func ==(lhs: Address, rhs: Address) -> Bool { + static func == (lhs: Address, rhs: Address) -> Bool { lhs.raw == rhs.raw && - lhs.domain == rhs.domain + lhs.domain == rhs.domain } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AddressUri.swift b/UnstoppableWallet/UnstoppableWallet/Models/AddressUri.swift index 1d3e323a9d..4d6ac592b6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AddressUri.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AddressUri.swift @@ -59,7 +59,7 @@ extension AddressUri { return [BlockchainType(uid: concreteUid)] } - if let type = BlockchainType.supported.first(where: {$0.uriScheme == scheme }) { + if let type = BlockchainType.supported.first(where: { $0.uriScheme == scheme }) { // For any evm types uses ethereum:_ scheme if EvmBlockchainManager.blockchainTypes.contains(type) { return EvmBlockchainManager.blockchainTypes diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AmountData.swift b/UnstoppableWallet/UnstoppableWallet/Models/AmountData.swift index 6f18965527..bb804983b7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AmountData.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AmountData.swift @@ -1,7 +1,7 @@ -import UIKit -import RxSwift import HsToolKit import MarketKit +import RxSwift +import UIKit enum AmountInfo { case coinValue(coinValue: CoinValue) @@ -9,27 +9,26 @@ enum AmountInfo { var formattedFull: String? { switch self { - case .coinValue(let coinValue): + case let .coinValue(coinValue): return coinValue.formattedFull - case .currencyValue(let currencyValue): + case let .currencyValue(currencyValue): return currencyValue.formattedFull } } var value: Decimal { switch self { - case .currencyValue(let currencyValue): return currencyValue.value - case .coinValue(let coinValue): return coinValue.value + case let .currencyValue(currencyValue): return currencyValue.value + case let .coinValue(coinValue): return coinValue.value } } var decimal: Int { switch self { - case .currencyValue(let currencyValue): return currencyValue.currency.decimal - case .coinValue(let coinValue): return coinValue.decimals + case let .currencyValue(currencyValue): return currencyValue.currency.decimal + case let .coinValue(coinValue): return coinValue.decimals } } - } struct AmountData { @@ -49,5 +48,4 @@ struct AmountData { return parts.joined(separator: " | ") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AppError.swift b/UnstoppableWallet/UnstoppableWallet/Models/AppError.swift index 4036a5955d..e59cf27a14 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AppError.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AppError.swift @@ -41,44 +41,41 @@ enum AppError: Error { case cannotEstimate case insufficientLiquidity } - } - extension AppError: LocalizedError { - var errorDescription: String? { switch self { case .noConnection: return "alert.no_internet".localized - case .invalidResponse(let reason): return reason - case .binance(let reason): + case let .invalidResponse(reason): return reason + case let .binance(reason): switch reason { case .memoRequired: return "error.send_binance.memo_required".localized case .onlyDigitsAllowed: return "error.send_binance.only_digits_allowed".localized } - case .zcash(let reason): + case let .zcash(reason): switch reason { case .sendToSelf: return "error.send.self_transfer".localized case .noReceiveAddress: return "send.error.invalid_address".localized case .seedRequired, .cantCreateKeys: return "Seed Required" } - case .ethereum(let reason): + case let .ethereum(reason): switch reason { case .insufficientBalanceWithFee: return "" // localized in modules - case .executionReverted(let message): return "ethereum_transaction.error.reverted".localized(message) + case let .executionReverted(message): return "ethereum_transaction.error.reverted".localized(message) case .lowerThanBaseGasLimit: return "ethereum_transaction.error.lower_than_base_gas_limit".localized case .nonceAlreadyInBlock: return "ethereum_transaction.error.nonce_already_in_block".localized case .replacementTransactionUnderpriced: return "ethereum_transaction.error.replacement_transaction_underpriced".localized case .transactionUnderpriced: return "ethereum_transaction.error.transaction_underpriced".localized case .tipsHigherThanMaxFee: return "ethereum_transaction.error.tips_higher_than_max_fee".localized } - case .oneInch(let reason): + case let .oneInch(reason): switch reason { case .insufficientBalanceWithFee: return "" // localized in modules case .cannotEstimate: return "" // localized in modules case .insufficientLiquidity: return "swap.one_inch.error.insufficient_liquidity.info".localized } - case .invalidWords(let count): + case let .invalidWords(count): return "restore_error.mnemonic_word_count".localized("\(count)") case .wordsChecksum: return "restore.checksum_error".localized @@ -87,7 +84,5 @@ extension AppError: LocalizedError { case .weakReference: return "Weak Reference" case .unknownError: return "Unknown Error" } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AppVersion.swift b/UnstoppableWallet/UnstoppableWallet/Models/AppVersion.swift index 1be834bf41..4331646552 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AppVersion.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AppVersion.swift @@ -22,7 +22,6 @@ struct AppVersion: Codable { } extension AppVersion: CustomStringConvertible { - var releaseNotesVersion: String { "\(major).\(minor)" } @@ -30,13 +29,12 @@ extension AppVersion: CustomStringConvertible { var description: String { let showBuildNumber = Bundle.main.object(forInfoDictionaryKey: "ShowBuildNumber") as? String == "true" - guard showBuildNumber, let build = build else { + guard showBuildNumber, let build else { return version } return version + " (\(build))" } - } extension AppVersion { @@ -46,4 +44,4 @@ extension AppVersion { case build case downgrade } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AppVersionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/AppVersionRecord.swift index 67420fb582..c122f2e08c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AppVersionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AppVersionRecord.swift @@ -37,5 +37,4 @@ class AppVersionRecord: Record { container[Columns.build] = build container[Columns.date] = date } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/AuthData.swift b/UnstoppableWallet/UnstoppableWallet/Models/AuthData.swift index 5c7035663f..4976f6d8e4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/AuthData.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/AuthData.swift @@ -27,5 +27,4 @@ class AuthData: NSObject, NSCoding { aCoder.encode(walletId, forKey: AuthData.walletIdKey) aCoder.encode(words, forKey: AuthData.wordsKey) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/BalancePrimaryValue.swift b/UnstoppableWallet/UnstoppableWallet/Models/BalancePrimaryValue.swift index c4dc1d4c76..f29ad54ddf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/BalancePrimaryValue.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/BalancePrimaryValue.swift @@ -15,5 +15,4 @@ enum BalancePrimaryValue: String, CaseIterable, Codable { case .currency: return "appearance.balance_value.coin_value".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/BitcoinCashCoinType.swift b/UnstoppableWallet/UnstoppableWallet/Models/BitcoinCashCoinType.swift index 45e56ee105..460682bcb1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/BitcoinCashCoinType.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/BitcoinCashCoinType.swift @@ -34,16 +34,13 @@ enum BitcoinCashCoinType: String, CaseIterable { var recommended: String { self == Self.default ? "blockchain_type.recommended".localized : "" } - } extension TokenType.AddressType { - var bitcoinCashCoinType: BitcoinCashCoinType { switch self { case .type0: return .type0 case .type145: return .type145 } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/BlockchainSettingRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/BlockchainSettingRecord.swift index db7fbac72a..18bd199321 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/BlockchainSettingRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/BlockchainSettingRecord.swift @@ -35,5 +35,4 @@ class BlockchainSettingRecord: Record { container[Columns.key] = key container[Columns.value] = value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Cex.swift b/UnstoppableWallet/UnstoppableWallet/Models/Cex.swift index 87e91fca3a..fcaf07acb5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Cex.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Cex.swift @@ -31,5 +31,4 @@ enum Cex: String, CaseIterable { case .binance: return RestoreBinanceModule.viewController(returnViewController: returnViewController) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexAccount.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexAccount.swift index a0feddec45..6ee8b8478d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexAccount.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexAccount.swift @@ -26,7 +26,7 @@ enum CexAccount { var uniqueId: String { switch self { - case .binance(let apiKey, let secret): return [Cex.binance.rawValue, apiKey, secret].joined(separator: Self.separator) + case let .binance(apiKey, secret): return [Cex.binance.rawValue, apiKey, secret].joined(separator: Self.separator) } } @@ -48,36 +48,32 @@ enum CexAccount { return nil } } - } extension CexAccount { - var assetProvider: ICexAssetProvider { switch self { - case .binance(let apiKey, let secret): return BinanceCexProvider(networkManager: App.shared.networkManager, apiKey: apiKey, secret: secret) + case let .binance(apiKey, secret): return BinanceCexProvider(networkManager: App.shared.networkManager, apiKey: apiKey, secret: secret) } } var depositProvider: ICexDepositProvider { switch self { - case .binance(let apiKey, let secret): return BinanceCexProvider(networkManager: App.shared.networkManager, apiKey: apiKey, secret: secret) + case let .binance(apiKey, secret): return BinanceCexProvider(networkManager: App.shared.networkManager, apiKey: apiKey, secret: secret) } } var withdrawHandler: ICexWithdrawHandler { switch self { - case .binance(let apiKey, let secret): + case let .binance(apiKey, secret): let provider = BinanceCexProvider(networkManager: App.shared.networkManager, apiKey: apiKey, secret: secret) return BinanceWithdrawHandler(provider: provider) } } - } extension CexAccount: Hashable { - - public static func ==(lhs: CexAccount, rhs: CexAccount) -> Bool { + public static func == (lhs: CexAccount, rhs: CexAccount) -> Bool { switch (lhs, rhs) { case (let .binance(lhsApiKey, lhsSecret), let .binance(rhsApiKey, rhsSecret)): return lhsApiKey == rhsApiKey && lhsSecret == rhsSecret @@ -86,11 +82,10 @@ extension CexAccount: Hashable { public func hash(into hasher: inout Hasher) { switch self { - case .binance(let apiKey, let secret): + case let .binance(apiKey, secret): hasher.combine(Cex.binance.rawValue) hasher.combine(apiKey) hasher.combine(secret) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexAsset.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexAsset.swift index 89a5207ba9..7f8d052fd9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexAsset.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexAsset.swift @@ -21,21 +21,18 @@ struct CexAsset { var coinName: String { coin?.name ?? name } - } extension CexAsset: Hashable { - func hash(into hasher: inout Hasher) { hasher.combine(id) } - static func ==(lhs: CexAsset, rhs: CexAsset) -> Bool { + static func == (lhs: CexAsset, rhs: CexAsset) -> Bool { lhs.id == rhs.id && lhs.name == rhs.name - && lhs.freeBalance == rhs.freeBalance && lhs.lockedBalance == rhs.lockedBalance - && lhs.depositEnabled == rhs.depositEnabled && lhs.withdrawEnabled == rhs.withdrawEnabled - && lhs.depositNetworks == rhs.depositNetworks && lhs.withdrawNetworks == rhs.withdrawNetworks - && lhs.coin == rhs.coin + && lhs.freeBalance == rhs.freeBalance && lhs.lockedBalance == rhs.lockedBalance + && lhs.depositEnabled == rhs.depositEnabled && lhs.withdrawEnabled == rhs.withdrawEnabled + && lhs.depositNetworks == rhs.depositNetworks && lhs.withdrawNetworks == rhs.withdrawNetworks + && lhs.coin == rhs.coin } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexAssetRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexAssetRecord.swift index 082fe8d397..c65247e98b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexAssetRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexAssetRecord.swift @@ -66,5 +66,4 @@ class CexAssetRecord: Record { container[Columns.withdrawNetworks] = withdrawNetworks.toJSONString() container[Columns.coinUid] = coinUid } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexAssetResponse.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexAssetResponse.swift index 4862ba48f5..875a7954f1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexAssetResponse.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexAssetResponse.swift @@ -13,17 +13,16 @@ struct CexAssetResponse { func record(accountId: String) -> CexAssetRecord { CexAssetRecord( - accountId: accountId, - id: id, - name: name, - freeBalance: freeBalance, - lockedBalance: lockedBalance, - depositEnabled: depositEnabled, - withdrawEnabled: withdrawEnabled, - depositNetworks: depositNetworks, - withdrawNetworks: withdrawNetworks, - coinUid: coinUid + accountId: accountId, + id: id, + name: name, + freeBalance: freeBalance, + lockedBalance: lockedBalance, + depositEnabled: depositEnabled, + withdrawEnabled: withdrawEnabled, + depositNetworks: depositNetworks, + withdrawNetworks: withdrawNetworks, + coinUid: coinUid ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetwork.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetwork.swift index 6ea5c70040..5e9a3653da 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetwork.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetwork.swift @@ -12,17 +12,14 @@ struct CexDepositNetwork { var networkName: String { blockchain?.name ?? name } - } extension CexDepositNetwork: Hashable { - func hash(into hasher: inout Hasher) { hasher.combine(id) } - static func ==(lhs: CexDepositNetwork, rhs: CexDepositNetwork) -> Bool { + static func == (lhs: CexDepositNetwork, rhs: CexDepositNetwork) -> Bool { lhs.id == rhs.id && lhs.name == rhs.name && lhs.isDefault == rhs.isDefault && lhs.enabled == rhs.enabled && lhs.minAmount == rhs.minAmount && lhs.blockchain == rhs.blockchain } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetworkRaw.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetworkRaw.swift index 17a5e6df39..f140ba37d6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetworkRaw.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexDepositNetworkRaw.swift @@ -1,6 +1,6 @@ import Foundation -import ObjectMapper import MarketKit +import ObjectMapper struct CexDepositNetworkRaw: ImmutableMappable { let id: String @@ -39,13 +39,12 @@ struct CexDepositNetworkRaw: ImmutableMappable { func cexDepositNetwork(blockchain: Blockchain?) -> CexDepositNetwork { CexDepositNetwork( - id: id, - name: name, - isDefault: isDefault, - enabled: enabled, - minAmount: minAmount, - blockchain: blockchain + id: id, + name: name, + isDefault: isDefault, + enabled: enabled, + minAmount: minAmount, + blockchain: blockchain ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetwork.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetwork.swift index c586efc822..dd7e434689 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetwork.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetwork.swift @@ -16,20 +16,17 @@ struct CexWithdrawNetwork { var networkName: String { blockchain?.name ?? name } - } extension CexWithdrawNetwork: Hashable { - func hash(into hasher: inout Hasher) { hasher.combine(id) } - static func ==(lhs: CexWithdrawNetwork, rhs: CexWithdrawNetwork) -> Bool { + static func == (lhs: CexWithdrawNetwork, rhs: CexWithdrawNetwork) -> Bool { lhs.id == rhs.id && lhs.name == rhs.name && lhs.isDefault == rhs.isDefault && lhs.enabled == rhs.enabled - && lhs.minAmount == rhs.minAmount && lhs.maxAmount == rhs.maxAmount - && lhs.fixedFee == rhs.fixedFee && lhs.feePercent == rhs.feePercent && lhs.minFee == rhs.minFee - && lhs.blockchain == rhs.blockchain + && lhs.minAmount == rhs.minAmount && lhs.maxAmount == rhs.maxAmount + && lhs.fixedFee == rhs.fixedFee && lhs.feePercent == rhs.feePercent && lhs.minFee == rhs.minFee + && lhs.blockchain == rhs.blockchain } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetworkRaw.swift b/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetworkRaw.swift index 9772fa63e5..161da17aa6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetworkRaw.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CexWithdrawNetworkRaw.swift @@ -1,6 +1,6 @@ import Foundation -import ObjectMapper import MarketKit +import ObjectMapper struct CexWithdrawNetworkRaw: ImmutableMappable { let id: String @@ -55,16 +55,16 @@ struct CexWithdrawNetworkRaw: ImmutableMappable { func cexWithdrawNetwork(blockchain: Blockchain?) -> CexWithdrawNetwork { CexWithdrawNetwork( - id: id, - name: name, - isDefault: isDefault, - enabled: enabled, - minAmount: minAmount, - maxAmount: maxAmount, - fixedFee: fixedFee, - feePercent: feePercent, - minFee: minFee, - blockchain: blockchain + id: id, + name: name, + isDefault: isDefault, + enabled: enabled, + minAmount: minAmount, + maxAmount: maxAmount, + fixedFee: fixedFee, + feePercent: feePercent, + minFee: minFee, + blockchain: blockchain ) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/CoinValue.swift b/UnstoppableWallet/UnstoppableWallet/Models/CoinValue.swift index 60535fa05d..523e04107d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/CoinValue.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/CoinValue.swift @@ -1,6 +1,6 @@ +import BigInt import Foundation import MarketKit -import BigInt struct CoinValue { let kind: Kind @@ -25,11 +25,9 @@ struct CoinValue { var formattedFull: String? { ValueFormatter.instance.formatFull(coinValue: self) } - } extension CoinValue { - enum Kind: Equatable { case token(token: Token) case coin(coin: Coin, decimals: Int) @@ -37,43 +35,40 @@ extension CoinValue { var token: Token? { switch self { - case .token(let token): return token - case .coin, .cexAsset: return nil + case let .token(token): return token + case .coin, .cexAsset: return nil } } var decimals: Int { switch self { - case .token(let token): return token.decimals - case .coin(_, let decimals): return decimals + case let .token(token): return token.decimals + case let .coin(_, decimals): return decimals case .cexAsset: return CexAsset.decimals } } var symbol: String { switch self { - case .token(let token): return token.coin.code - case .coin(let coin, _): return coin.code - case .cexAsset(let cexAsset): return cexAsset.coinCode + case let .token(token): return token.coin.code + case let .coin(coin, _): return coin.code + case let .cexAsset(cexAsset): return cexAsset.coinCode } } - static func ==(lhs: Kind, rhs: Kind) -> Bool { + static func == (lhs: Kind, rhs: Kind) -> Bool { switch (lhs, rhs) { - case (.token(let lhsToken), .token(let rhsToken)): return lhsToken == rhsToken - case (.coin(let lhsCoin, let lhsDecimals), .coin(let rhsCoin, let rhsDecimals)): return lhsCoin == rhsCoin && lhsDecimals == rhsDecimals - case (.cexAsset(let lhsCexAsset), .cexAsset(let rhsCexAsset)): return lhsCexAsset == rhsCexAsset + case let (.token(lhsToken), .token(rhsToken)): return lhsToken == rhsToken + case let (.coin(lhsCoin, lhsDecimals), .coin(rhsCoin, rhsDecimals)): return lhsCoin == rhsCoin && lhsDecimals == rhsDecimals + case let (.cexAsset(lhsCexAsset), .cexAsset(rhsCexAsset)): return lhsCexAsset == rhsCexAsset default: return false } } } - } extension CoinValue: Equatable { - - public static func ==(lhs: CoinValue, rhs: CoinValue) -> Bool { + public static func == (lhs: CoinValue, rhs: CoinValue) -> Bool { lhs.kind == rhs.kind && lhs.value == rhs.value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Contact.swift b/UnstoppableWallet/UnstoppableWallet/Models/Contact.swift index 89f6e0b1d6..eae71f76d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Contact.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Contact.swift @@ -36,7 +36,7 @@ class ContactAddress: Codable, ImmutableMappable, Hashable, Equatable { } } -extension Array where Element == ContactAddress { +extension [ContactAddress] { static func == (lhs: [ContactAddress], rhs: [ContactAddress]) -> Bool { Set(lhs) == Set(rhs) } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/ConvertedError.swift b/UnstoppableWallet/UnstoppableWallet/Models/ConvertedError.swift index 266ad2d4b9..d7e6e3be84 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/ConvertedError.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/ConvertedError.swift @@ -1,8 +1,8 @@ -import Foundation -import BitcoinCore import BinanceChainKit +import BitcoinCore import Eip20Kit import EvmKit +import Foundation import HdWalletKit import Hodler import HsToolKit @@ -17,14 +17,12 @@ protocol ConvertibleError { } extension Error { - var convertedError: Error { if let error = self as? ConvertibleError { return error.convertedError } return self } - } // converted errors @@ -33,7 +31,7 @@ extension NetworkManager.RequestError: ConvertibleError { var convertedError: Error { switch self { case .noResponse: return AppError.noConnection - case .invalidResponse(let statusCode, let data): + case let .invalidResponse(statusCode, data): let description: String? switch data { case let data as Data: description = String(data: data, encoding: .utf8) @@ -64,7 +62,7 @@ extension BinanceError: ConvertibleError { extension Mnemonic.ValidationError: ConvertibleError { var convertedError: Error { switch self { - case .invalidWords(count: let count): + case let .invalidWords(count: count): return AppError.invalidWords(count: count) case .invalidChecksum: return AppError.wordsChecksum @@ -93,19 +91,19 @@ extension EvmKit.Kit.SyncError: ConvertibleError { extension EvmKit.Address.ValidationError: ConvertibleError { var convertedError: Error { - AppError.addressInvalid + AppError.addressInvalid } } extension BinanceChainKit.CoderError: ConvertibleError { var convertedError: Error { - AppError.addressInvalid + AppError.addressInvalid } } extension HodlerPluginError: ConvertibleError { var convertedError: Error { - AppError.notSupportedByHodler + AppError.notSupportedByHodler } } @@ -117,15 +115,14 @@ extension BitcoinCoreErrors.AddressConversionErrors: ConvertibleError { extension HsToolKit.WebSocketStateError: ConvertibleError { var convertedError: Error { - return AppError.noConnection + AppError.noConnection } } extension EvmKit.JsonRpcResponse.ResponseError: ConvertibleError { - var convertedError: Error { switch self { - case .rpcError(let rpcError): + case let .rpcError(rpcError): if rpcError.message == "insufficient funds for transfer" || rpcError.message.starts(with: "gas required exceeds allowance") { return AppError.ethereum(reason: .insufficientBalanceWithFee) } @@ -158,26 +155,21 @@ extension EvmKit.JsonRpcResponse.ResponseError: ConvertibleError { default: return self } } - } extension OneInchKit.Kit.SwapError: ConvertibleError { - var convertedError: Error { switch self { case .notEnough: return AppError.oneInch(reason: .insufficientBalanceWithFee) case .cannotEstimate: return AppError.oneInch(reason: .cannotEstimate) } } - } extension OneInchKit.Kit.QuoteError: ConvertibleError { - var convertedError: Error { switch self { - case .insufficientLiquidity: return AppError.oneInch(reason: .insufficientLiquidity) + case .insufficientLiquidity: return AppError.oneInch(reason: .insufficientLiquidity) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/DataStatus.swift b/UnstoppableWallet/UnstoppableWallet/Models/DataStatus.swift index 664b0d5870..08a4cc649a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/DataStatus.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/DataStatus.swift @@ -7,7 +7,7 @@ enum DataStatus { case completed(T) init(data: T?) { - if let data = data { + if let data { self = .completed(data) } else { self = .loading @@ -23,13 +23,13 @@ enum DataStatus { loadingRelay?.accept(false) } - if case .completed(let result) = self { + if case let .completed(result) = self { completedRelay?.accept(mapper(result)) } else { completedRelay?.accept(nil) } - if case .failed(let error) = self { + if case let .failed(error) = self { failedRelay?.accept(error) } else { failedRelay?.accept(nil) @@ -42,12 +42,12 @@ enum DataStatus { } switch first { - case .failed(let error): return .failed(error) + case let .failed(error): return .failed(error) default: () } switch second { - case .failed(let error): return .failed(error) + case let .failed(error): return .failed(error) default: () } @@ -57,16 +57,16 @@ enum DataStatus { func map(_ transform: (T) -> R, transformError: ((Error) -> Error)? = nil) -> DataStatus { switch self { case .loading: return .loading - case .failed(let error): return .failed(transformError?(error) ?? error) - case .completed(let data): return .completed(transform(data)) + case let .failed(error): return .failed(transformError?(error) ?? error) + case let .completed(data): return .completed(transform(data)) } } func flatMap(_ transform: (T) -> R?) -> DataStatus? { switch self { case .loading: return .loading - case .failed(let error): return .failed(error) - case .completed(let data): + case let .failed(error): return .failed(error) + case let .completed(data): if let result = transform(data) { return .completed(result) } @@ -87,33 +87,28 @@ enum DataStatus { } return nil } - } extension DataStatus: Equatable { - - public static func ==(lhs: DataStatus, rhs: DataStatus) -> Bool { + public static func == (lhs: DataStatus, rhs: DataStatus) -> Bool { switch (lhs, rhs) { case (.loading, .loading), (.completed, .completed), (.failed, .failed): return true default: return false } } - } extension DataStatus where T: Equatable { - - func equalTo(_ rhs: DataStatus) -> Bool { + func equalTo(_ rhs: DataStatus) -> Bool { switch (self, rhs) { case (.loading, .loading): return true - case (.failed(let lhsValue), .failed(let rhsValue)): + case let (.failed(lhsValue), .failed(rhsValue)): return lhsValue.smartDescription == rhsValue.smartDescription - case (.completed(let lhsValue), .completed(let rhsValue)): + case let (.completed(lhsValue), .completed(rhsValue)): return lhsValue == rhsValue default: return false } } - } struct FallibleData { diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_10.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_10.swift index 090fef68c0..3b7b33a747 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_10.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_10.swift @@ -63,5 +63,4 @@ class AccountRecord_v_0_10: Record { container[Columns.dataKey] = dataKey container[Columns.eosAccount] = eosAccount } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_19.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_19.swift index 5dfc1010c1..0696feb100 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_19.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_19.swift @@ -62,5 +62,4 @@ class AccountRecord_v_0_19: Record { container[Columns.dataKey] = dataKey container[Columns.eosAccount] = eosAccount } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_20.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_20.swift index daf37511e1..b33c809979 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_20.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_20.swift @@ -58,5 +58,4 @@ class AccountRecord_v_0_20: Record { container[Columns.birthdayHeightKey] = birthdayHeightKey container[Columns.dataKey] = dataKey } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_36.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_36.swift index 9b66b84c21..7aa2a81699 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_36.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/AccountRecord_v_0_36.swift @@ -58,5 +58,4 @@ class AccountRecord_v_0_36: Record { container[Columns.dataKey] = dataKey container[Columns.bip39Compliant] = bip39Compliant } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/ActiveAccount_v_0_36.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/ActiveAccount_v_0_36.swift index ba9700af9f..aae2605bc5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/ActiveAccount_v_0_36.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/ActiveAccount_v_0_36.swift @@ -28,5 +28,4 @@ class ActiveAccount_v_0_36: Record { container[Columns.uniqueId] = uniqueId container[Columns.accountId] = accountId } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/BlockchainSettingRecord_v_0_24.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/BlockchainSettingRecord_v_0_24.swift index f9ee1d8796..ff9c8a8049 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/BlockchainSettingRecord_v_0_24.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/BlockchainSettingRecord_v_0_24.swift @@ -37,5 +37,4 @@ class BlockchainSettingRecord_v_0_24: Record { container[Columns.key] = key container[Columns.value] = value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinRecord_v19.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinRecord_v19.swift index cf6ee7e707..33eae182f9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinRecord_v19.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinRecord_v19.swift @@ -55,5 +55,4 @@ class CoinRecord_v19: Record { container[Columns.erc20Address] = erc20Address container[Columns.bep2Symbol] = bep2Symbol } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinType.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinType.swift index 91c8879ea9..d0e16d8220 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinType.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CoinType.swift @@ -48,24 +48,24 @@ public enum CoinType: Decodable { case "polygon": self = .polygon case "ethereum-optimism": self = .ethereumOptimism case "ethereum-arbitrum-one": self = .ethereumArbitrumOne - case "erc20": if let address = address { self = .erc20(address: address) } else { return nil } - case "bep20": if let address = address { self = .bep20(address: address) } else { return nil } - case "polygon-pos": if let address = address { self = .mrc20(address: address) } else { return nil } - case "optimistic-ethereum": if let address = address { self = .optimismErc20(address: address) } else { return nil } - case "arbitrum-one": if let address = address { self = .arbitrumOneErc20(address: address) } else { return nil } - case "bep2": if let symbol = symbol { self = .bep2(symbol: symbol) } else { return nil } - case "avalanche": if let address = address { self = .avalanche(address: address) } else { return nil } - case "fantom": if let address = address { self = .fantom(address: address) } else { return nil } - case "harmony-shard-0": if let address = address { self = .harmonyShard0(address: address) } else { return nil } - case "huobi-token": if let address = address { self = .huobiToken(address: address) } else { return nil } - case "iotex": if let address = address { self = .iotex(address: address) } else { return nil } - case "moonriver": if let address = address { self = .moonriver(address: address) } else { return nil } - case "okex-chain": if let address = address { self = .okexChain(address: address) } else { return nil } - case "solana": if let address = address { self = .solana(address: address) } else { return nil } - case "sora": if let address = address { self = .sora(address: address) } else { return nil } - case "tomochain": if let address = address { self = .tomochain(address: address) } else { return nil } - case "xdai": if let address = address { self = .xdai(address: address) } else { return nil } - case "trc20": if let address = address { self = .trc20(address: address) } else { return nil } + case "erc20": if let address { self = .erc20(address: address) } else { return nil } + case "bep20": if let address { self = .bep20(address: address) } else { return nil } + case "polygon-pos": if let address { self = .mrc20(address: address) } else { return nil } + case "optimistic-ethereum": if let address { self = .optimismErc20(address: address) } else { return nil } + case "arbitrum-one": if let address { self = .arbitrumOneErc20(address: address) } else { return nil } + case "bep2": if let symbol { self = .bep2(symbol: symbol) } else { return nil } + case "avalanche": if let address { self = .avalanche(address: address) } else { return nil } + case "fantom": if let address { self = .fantom(address: address) } else { return nil } + case "harmony-shard-0": if let address { self = .harmonyShard0(address: address) } else { return nil } + case "huobi-token": if let address { self = .huobiToken(address: address) } else { return nil } + case "iotex": if let address { self = .iotex(address: address) } else { return nil } + case "moonriver": if let address { self = .moonriver(address: address) } else { return nil } + case "okex-chain": if let address { self = .okexChain(address: address) } else { return nil } + case "solana": if let address { self = .solana(address: address) } else { return nil } + case "sora": if let address { self = .sora(address: address) } else { return nil } + case "tomochain": if let address { self = .tomochain(address: address) } else { return nil } + case "xdai": if let address { self = .xdai(address: address) } else { return nil } + case "trc20": if let address { self = .trc20(address: address) } else { return nil } default: self = .unsupported(type: type) } } @@ -82,33 +82,31 @@ public enum CoinType: Decodable { case .polygon: return (type: "polygon", address: nil, symbol: nil) case .ethereumOptimism: return (type: "ethereum-optimism", address: nil, symbol: nil) case .ethereumArbitrumOne: return (type: "ethereum-arbitrum-one", address: nil, symbol: nil) - case .erc20(let address): return (type: "erc20", address: address, symbol: nil) - case .bep20(let address): return (type: "bep20", address: address, symbol: nil) - case .mrc20(let address): return (type: "polygon-pos", address: address, symbol: nil) - case .optimismErc20(let address): return (type: "optimistic-ethereum", address: address, symbol: nil) - case .arbitrumOneErc20(let address): return (type: "arbitrum-one", address: address, symbol: nil) - case .bep2(let symbol): return (type: "bep2", address: nil, symbol: symbol) - case .avalanche(let address): return (type: "avalanche", address: address, symbol: nil) - case .fantom(let address): return (type: "fantom", address: address, symbol: nil) - case .harmonyShard0(let address): return (type: "harmony-shard-0", address: address, symbol: nil) - case .huobiToken(let address): return (type: "huobi-token", address: address, symbol: nil) - case .iotex(let address): return (type: "iotex", address: address, symbol: nil) - case .moonriver(let address): return (type: "moonriver", address: address, symbol: nil) - case .okexChain(let address): return (type: "okex-chain", address: address, symbol: nil) - case .solana(let address): return (type: "solana", address: address, symbol: nil) - case .sora(let address): return (type: "sora", address: address, symbol: nil) - case .tomochain(let address): return (type: "tomochain", address: address, symbol: nil) - case .xdai(let address): return (type: "xdai", address: address, symbol: nil) - case .trc20(let address): return (type: "trc20", address: address, symbol: nil) - case .unsupported(let type): return (type: type, address: nil, symbol: nil) + case let .erc20(address): return (type: "erc20", address: address, symbol: nil) + case let .bep20(address): return (type: "bep20", address: address, symbol: nil) + case let .mrc20(address): return (type: "polygon-pos", address: address, symbol: nil) + case let .optimismErc20(address): return (type: "optimistic-ethereum", address: address, symbol: nil) + case let .arbitrumOneErc20(address): return (type: "arbitrum-one", address: address, symbol: nil) + case let .bep2(symbol): return (type: "bep2", address: nil, symbol: symbol) + case let .avalanche(address): return (type: "avalanche", address: address, symbol: nil) + case let .fantom(address): return (type: "fantom", address: address, symbol: nil) + case let .harmonyShard0(address): return (type: "harmony-shard-0", address: address, symbol: nil) + case let .huobiToken(address): return (type: "huobi-token", address: address, symbol: nil) + case let .iotex(address): return (type: "iotex", address: address, symbol: nil) + case let .moonriver(address): return (type: "moonriver", address: address, symbol: nil) + case let .okexChain(address): return (type: "okex-chain", address: address, symbol: nil) + case let .solana(address): return (type: "solana", address: address, symbol: nil) + case let .sora(address): return (type: "sora", address: address, symbol: nil) + case let .tomochain(address): return (type: "tomochain", address: address, symbol: nil) + case let .xdai(address): return (type: "xdai", address: address, symbol: nil) + case let .trc20(address): return (type: "trc20", address: address, symbol: nil) + case let .unsupported(type): return (type: type, address: nil, symbol: nil) } } - } extension CoinType: Equatable { - - public static func ==(lhs: CoinType, rhs: CoinType) -> Bool { + public static func == (lhs: CoinType, rhs: CoinType) -> Bool { switch (lhs, rhs) { case (.bitcoin, .bitcoin): return true case (.bitcoinCash, .bitcoinCash): return true @@ -120,37 +118,34 @@ extension CoinType: Equatable { case (.polygon, .polygon): return true case (.ethereumOptimism, .ethereumOptimism): return true case (.ethereumArbitrumOne, .ethereumArbitrumOne): return true - case (.erc20(let lhsAddress), .erc20(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.bep20(let lhsAddress), .bep20(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.mrc20(let lhsAddress), .mrc20(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.optimismErc20(let lhsAddress), .optimismErc20(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.arbitrumOneErc20(let lhsAddress), .arbitrumOneErc20(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.bep2(let lhsSymbol), .bep2(let rhsSymbol)): return lhsSymbol == rhsSymbol - case (.avalanche(let lhsAddress), .avalanche(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.fantom(let lhsAddress), .fantom(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.harmonyShard0(let lhsAddress), .harmonyShard0(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.huobiToken(let lhsAddress), .huobiToken(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.iotex(let lhsAddress), .iotex(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.moonriver(let lhsAddress), .moonriver(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.okexChain(let lhsAddress), .okexChain(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.solana(let lhsAddress), .solana(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.sora(let lhsAddress), .sora(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.tomochain(let lhsAddress), .tomochain(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.xdai(let lhsAddress), .xdai(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.trc20(let lhsAddress), .trc20(let rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() - case (.unsupported(let lhsType), .unsupported(let rhsType)): return lhsType == rhsType + case let (.erc20(lhsAddress), .erc20(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.bep20(lhsAddress), .bep20(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.mrc20(lhsAddress), .mrc20(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.optimismErc20(lhsAddress), .optimismErc20(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.arbitrumOneErc20(lhsAddress), .arbitrumOneErc20(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.bep2(lhsSymbol), .bep2(rhsSymbol)): return lhsSymbol == rhsSymbol + case let (.avalanche(lhsAddress), .avalanche(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.fantom(lhsAddress), .fantom(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.harmonyShard0(lhsAddress), .harmonyShard0(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.huobiToken(lhsAddress), .huobiToken(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.iotex(lhsAddress), .iotex(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.moonriver(lhsAddress), .moonriver(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.okexChain(lhsAddress), .okexChain(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.solana(lhsAddress), .solana(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.sora(lhsAddress), .sora(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.tomochain(lhsAddress), .tomochain(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.xdai(lhsAddress), .xdai(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.trc20(lhsAddress), .trc20(rhsAddress)): return lhsAddress.lowercased() == rhsAddress.lowercased() + case let (.unsupported(lhsType), .unsupported(rhsType)): return lhsType == rhsType default: return false } } - } extension CoinType: Hashable { - public func hash(into hasher: inout Hasher) { hasher.combine(id) } - } extension CoinType: Identifiable { @@ -211,32 +206,30 @@ extension CoinType: Identifiable { case .polygon: return "polygon" case .ethereumOptimism: return "ethereumOptimism" case .ethereumArbitrumOne: return "ethereumArbitrumOne" - case .erc20(let address): return ["erc20", address].joined(separator: "|") - case .bep20(let address): return ["bep20", address].joined(separator: "|") - case .mrc20(let address): return ["mrc20", address].joined(separator: "|") - case .optimismErc20(let address): return ["optimismErc20", address].joined(separator: "|") - case .arbitrumOneErc20(let address): return ["arbitrumOneErc20", address].joined(separator: "|") - case .bep2(let symbol): return ["bep2", symbol].joined(separator: "|") - case .avalanche(let address): return ["avalanche", address].joined(separator: "|") - case .fantom(let address): return ["fantom", address].joined(separator: "|") - case .harmonyShard0(let address): return ["harmonyShard0", address].joined(separator: "|") - case .huobiToken(let address): return ["huobiToken", address].joined(separator: "|") - case .iotex(let address): return ["iotex", address].joined(separator: "|") - case .moonriver(let address): return ["moonriver", address].joined(separator: "|") - case .okexChain(let address): return ["okexChain", address].joined(separator: "|") - case .solana(let address): return ["solana", address].joined(separator: "|") - case .sora(let address): return ["sora", address].joined(separator: "|") - case .tomochain(let address): return ["tomochain", address].joined(separator: "|") - case .xdai(let address): return ["xdai", address].joined(separator: "|") - case .trc20(let address): return ["trc20", address].joined(separator: "|") - case .unsupported(let type): return ["unsupported", type].joined(separator: "|") + case let .erc20(address): return ["erc20", address].joined(separator: "|") + case let .bep20(address): return ["bep20", address].joined(separator: "|") + case let .mrc20(address): return ["mrc20", address].joined(separator: "|") + case let .optimismErc20(address): return ["optimismErc20", address].joined(separator: "|") + case let .arbitrumOneErc20(address): return ["arbitrumOneErc20", address].joined(separator: "|") + case let .bep2(symbol): return ["bep2", symbol].joined(separator: "|") + case let .avalanche(address): return ["avalanche", address].joined(separator: "|") + case let .fantom(address): return ["fantom", address].joined(separator: "|") + case let .harmonyShard0(address): return ["harmonyShard0", address].joined(separator: "|") + case let .huobiToken(address): return ["huobiToken", address].joined(separator: "|") + case let .iotex(address): return ["iotex", address].joined(separator: "|") + case let .moonriver(address): return ["moonriver", address].joined(separator: "|") + case let .okexChain(address): return ["okexChain", address].joined(separator: "|") + case let .solana(address): return ["solana", address].joined(separator: "|") + case let .sora(address): return ["sora", address].joined(separator: "|") + case let .tomochain(address): return ["tomochain", address].joined(separator: "|") + case let .xdai(address): return ["xdai", address].joined(separator: "|") + case let .trc20(address): return ["trc20", address].joined(separator: "|") + case let .unsupported(type): return ["unsupported", type].joined(separator: "|") } } - } extension CoinType: CustomStringConvertible { - public var description: String { switch self { case .bitcoin: return "bitcoin" @@ -249,26 +242,25 @@ extension CoinType: CustomStringConvertible { case .polygon: return "polygon" case .ethereumOptimism: return "ethereumOptimism" case .ethereumArbitrumOne: return "ethereumArbitrumOne" - case .erc20(let address): return ["erc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .bep20(let address): return ["bep20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .mrc20(let address): return ["mrc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .optimismErc20(let address): return ["optimismErc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .arbitrumOneErc20(let address): return ["arbitrumOneErc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .bep2(let symbol): return ["bep2", symbol].joined(separator: "|") - case .avalanche(let address): return ["avalanche", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .fantom(let address): return ["fantom", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .harmonyShard0(let address): return ["harmonyShard0", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .huobiToken(let address): return ["huobiToken", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .iotex(let address): return ["iotex", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .moonriver(let address): return ["moonriver", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .okexChain(let address): return ["okexChain", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .solana(let address): return ["solana", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .sora(let address): return ["sora", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .tomochain(let address): return ["tomochain", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .xdai(let address): return ["xdai", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .trc20(let address): return ["trc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") - case .unsupported(let type): return ["unsupported", type].joined(separator: "|") + case let .erc20(address): return ["erc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .bep20(address): return ["bep20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .mrc20(address): return ["mrc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .optimismErc20(address): return ["optimismErc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .arbitrumOneErc20(address): return ["arbitrumOneErc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .bep2(symbol): return ["bep2", symbol].joined(separator: "|") + case let .avalanche(address): return ["avalanche", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .fantom(address): return ["fantom", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .harmonyShard0(address): return ["harmonyShard0", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .huobiToken(address): return ["huobiToken", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .iotex(address): return ["iotex", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .moonriver(address): return ["moonriver", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .okexChain(address): return ["okexChain", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .solana(address): return ["solana", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .sora(address): return ["sora", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .tomochain(address): return ["tomochain", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .xdai(address): return ["xdai", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .trc20(address): return ["trc20", "\(address.prefix(4))...\(address.suffix(2))"].joined(separator: "|") + case let .unsupported(type): return ["unsupported", type].joined(separator: "|") } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CustomToken.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CustomToken.swift index 2adadef290..6228d93869 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CustomToken.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/CustomToken.swift @@ -32,5 +32,4 @@ class CustomToken: Record { container[Columns.coinTypeId] = coinTypeId container[Columns.decimals] = decimals } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_10.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_10.swift index cad4ecbacd..73654f9eae 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_10.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_10.swift @@ -41,5 +41,4 @@ class EnabledWallet_v_0_10: Record { override class var databaseTableName: String { "enabled_wallets" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_13.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_13.swift index caefd2b764..e4c8b6714e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_13.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_13.swift @@ -40,5 +40,4 @@ class EnabledWallet_v_0_13: Record { container[Columns.derivation] = derivation container[Columns.syncMode] = syncMode } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_20.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_20.swift index 16eed7a8ed..0342366b73 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_20.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_20.swift @@ -30,5 +30,4 @@ class EnabledWallet_v_0_20: Record { container[Columns.coinId] = coinId container[Columns.accountId] = accountId } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_25.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_25.swift index 7b86b62fba..e36060d658 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_25.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_25.swift @@ -47,5 +47,4 @@ class EnabledWallet_v_0_25: Record { container[Columns.coinCode] = coinCode container[Columns.coinDecimals] = coinDecimals } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_34.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_34.swift index 5607b5193c..d8a9b05561 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_34.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/EnabledWallet_v_0_34.swift @@ -19,6 +19,7 @@ class EnabledWallet_v_0_34: Record { self.tokenDecimals = tokenDecimals super.init() } + override class var databaseTableName: String { "enabled_wallets" } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/FavoriteCoinRecord_v_0_22.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/FavoriteCoinRecord_v_0_22.swift index cd1c09a1c5..f811fd90c3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/FavoriteCoinRecord_v_0_22.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/FavoriteCoinRecord_v_0_22.swift @@ -1,7 +1,7 @@ -//import GRDB -//import MarketKit +// import GRDB +// import MarketKit // -//class FavoriteCoinRecord_v_0_22: Record { +// class FavoriteCoinRecord_v_0_22: Record { // let coinType: CoinType // // init(coinType: CoinType) { @@ -29,4 +29,4 @@ // container[Columns.coinType] = coinType.id // } // -//} +// } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/RestoreSettingRecord_v_0_25.swift b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/RestoreSettingRecord_v_0_25.swift index 8e9be6bfa5..a20e471018 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/RestoreSettingRecord_v_0_25.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Deprecated/RestoreSettingRecord_v_0_25.swift @@ -38,5 +38,4 @@ class RestoreSettingRecord_v_0_25: Record { container[Columns.key] = key container[Columns.value] = value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EnabledWallet.swift b/UnstoppableWallet/UnstoppableWallet/Models/EnabledWallet.swift index fe8413a317..acae98fc5c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EnabledWallet.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EnabledWallet.swift @@ -44,5 +44,4 @@ class EnabledWallet: Record { container[Columns.coinCode] = coinCode container[Columns.tokenDecimals] = tokenDecimals } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache.swift b/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache.swift index ea675cb9f7..20dd3b1848 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache.swift @@ -44,5 +44,4 @@ class EnabledWalletCache: Record { container[Columns.accountId] = accountId container[Columns.balances] = balances } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache_v_0_36.swift b/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache_v_0_36.swift index f4bac69aff..a494cfc474 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache_v_0_36.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EnabledWalletCache_v_0_36.swift @@ -28,7 +28,7 @@ class EnabledWalletCache_v_0_36: Record { } enum Columns: String, ColumnExpression { - case tokenQueryId, accountId, balance, balanceLocked // todo: migration - remove coinSettingsId + case tokenQueryId, accountId, balance, balanceLocked // TODO: migration - remove coinSettingsId } required init(row: Row) throws { @@ -47,5 +47,4 @@ class EnabledWalletCache_v_0_36: Record { container[Columns.balance] = balance container[Columns.balanceLocked] = balanceLocked } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EvmAccountRestoreState.swift b/UnstoppableWallet/UnstoppableWallet/Models/EvmAccountRestoreState.swift index 96603487b3..d46fad7179 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EvmAccountRestoreState.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EvmAccountRestoreState.swift @@ -34,5 +34,4 @@ class EvmAccountRestoreState: Record { container[Columns.blockchainUid] = blockchainUid container[Columns.restored] = restored } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EvmAddressLabel.swift b/UnstoppableWallet/UnstoppableWallet/Models/EvmAddressLabel.swift index 0f4a64141f..b987807f28 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EvmAddressLabel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EvmAddressLabel.swift @@ -22,7 +22,7 @@ class EvmAddressLabel: Record, ImmutableMappable { } required init(map: Map) throws { - address = (try map.value("address") as String).lowercased() + address = try (map.value("address") as String).lowercased() label = try map.value("label") super.init() @@ -39,5 +39,4 @@ class EvmAddressLabel: Record, ImmutableMappable { container[Columns.address] = address container[Columns.label] = label } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EvmMethodLabel.swift b/UnstoppableWallet/UnstoppableWallet/Models/EvmMethodLabel.swift index beea72ff0d..b70fda5ae9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EvmMethodLabel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EvmMethodLabel.swift @@ -22,7 +22,7 @@ class EvmMethodLabel: Record, ImmutableMappable { } required init(map: Map) throws { - methodId = (try map.value("method_id") as String).lowercased() + methodId = try (map.value("method_id") as String).lowercased() label = try map.value("label") super.init() @@ -39,5 +39,4 @@ class EvmMethodLabel: Record, ImmutableMappable { container[Columns.methodId] = methodId container[Columns.label] = label } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSource.swift b/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSource.swift index 806f969b18..0f15787c82 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSource.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation class EvmSyncSource { let name: String @@ -18,24 +18,19 @@ class EvmSyncSource { default: return false } } - } extension EvmSyncSource: Equatable { - - static func ==(lhs: EvmSyncSource, rhs: EvmSyncSource) -> Bool { + static func == (lhs: EvmSyncSource, rhs: EvmSyncSource) -> Bool { lhs.rpcSource.url == rhs.rpcSource.url } - } extension RpcSource { - var url: URL { switch self { - case .http(let urls, _): return urls[0] - case .webSocket(let url, _): return url + case let .http(urls, _): return urls[0] + case let .webSocket(url, _): return url } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSourceRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSourceRecord.swift index 8d85a9cab6..b8851ebb62 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSourceRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EvmSyncSourceRecord.swift @@ -34,5 +34,4 @@ class EvmSyncSourceRecord: Record { container[Columns.url] = url container[Columns.auth] = auth } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/EvmUpdateStatus.swift b/UnstoppableWallet/UnstoppableWallet/Models/EvmUpdateStatus.swift index b0f30cc5e9..054835eac5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/EvmUpdateStatus.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/EvmUpdateStatus.swift @@ -9,5 +9,4 @@ class EvmUpdateStatus: ImmutableMappable { methodLabels = try map.value("evm_method_labels") addressLabels = try map.value("address_labels") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Faq.swift b/UnstoppableWallet/UnstoppableWallet/Models/Faq.swift index 0a80a0d79f..7ad668d70d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Faq.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Faq.swift @@ -14,7 +14,6 @@ struct Faq: ImmutableMappable { text = try map.value("title") fileUrl = try map.value("markdown") } - } struct FaqSection { diff --git a/UnstoppableWallet/UnstoppableWallet/Models/FavoriteCoinRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/FavoriteCoinRecord.swift index fccef4a3f2..79216480b9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/FavoriteCoinRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/FavoriteCoinRecord.swift @@ -9,7 +9,6 @@ class FavoriteCoinRecord: Record { super.init() } - override class var databaseTableName: String { "favorite_coins" } @@ -27,5 +26,4 @@ class FavoriteCoinRecord: Record { override func encode(to container: inout PersistenceContainer) { container[Columns.coinUid] = coinUid } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/FeeRateState.swift b/UnstoppableWallet/UnstoppableWallet/Models/FeeRateState.swift index 6c12154348..50f84f0df5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/FeeRateState.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/FeeRateState.swift @@ -13,17 +13,16 @@ enum FeeRateState { } var isValid: Bool { - if case .value(_) = self { + if case .value = self { return true } return false } var isError: Bool { - if case .error(_) = self { + if case .error = self { return true } return false } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Guide.swift b/UnstoppableWallet/UnstoppableWallet/Models/Guide.swift index c138769da2..3654f0cf12 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Guide.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Guide.swift @@ -19,11 +19,9 @@ struct GuideCategory: ImmutableMappable { guideMap[language] ?? guideMap[fallbackLanguage] } } - } extension GuideCategory { - class GuideTransform: TransformType { typealias Object = [[String: Guide]] typealias JSON = Any @@ -44,12 +42,10 @@ extension GuideCategory { } } - func transformToJSON(_ value: [[String: Guide]]?) -> Any? { + func transformToJSON(_: [[String: Guide]]?) -> Any? { fatalError("transformToJSON(_:) has not been implemented") } - } - } struct Guide: ImmutableMappable { @@ -74,7 +70,6 @@ struct Guide: ImmutableMappable { } extension Guide { - class DateTransform: TransformType { private static let dateFormatter: DateFormatter = { let formatter = DateFormatter() @@ -93,7 +88,7 @@ extension Guide { return DateTransform.dateFormatter.date(from: value) } - func transformToJSON(_ value: Date?) -> String? { + func transformToJSON(_: Date?) -> String? { fatalError("transformToJSON(_:) has not been implemented") } } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/LaunchScreen.swift b/UnstoppableWallet/UnstoppableWallet/Models/LaunchScreen.swift index 6b4e4ec30c..875c86d711 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/LaunchScreen.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/LaunchScreen.swift @@ -21,7 +21,6 @@ enum LaunchScreen: String, CaseIterable { case .watchlist: return "star_24" } } - } extension LaunchScreen: Codable { diff --git a/UnstoppableWallet/UnstoppableWallet/Models/LogRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/LogRecord.swift index 94867ef89e..9c1351e11a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/LogRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/LogRecord.swift @@ -54,5 +54,4 @@ class LogRecord: Record { container[Columns.context] = context container[Columns.message] = message } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/MnemonicDerivation.swift b/UnstoppableWallet/UnstoppableWallet/Models/MnemonicDerivation.swift index 756257de2b..1aa0d49c0b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/MnemonicDerivation.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/MnemonicDerivation.swift @@ -1,5 +1,5 @@ -import MarketKit import HdWalletKit +import MarketKit enum MnemonicDerivation: String, CaseIterable { static let `default` = bip84 @@ -52,11 +52,9 @@ enum MnemonicDerivation: String, CaseIterable { var recommended: String { self == Self.default ? "blockchain_type.recommended".localized : "" } - } extension Purpose { - var mnemonicDerivation: MnemonicDerivation { switch self { case .bip44: return .bip44 @@ -65,11 +63,9 @@ extension Purpose { case .bip86: return .bip86 } } - } extension TokenType.Derivation { - var mnemonicDerivation: MnemonicDerivation { switch self { case .bip44: return .bip44 @@ -78,5 +74,4 @@ extension TokenType.Derivation { case .bip86: return .bip86 } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftAssetBriefMetadata.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftAssetBriefMetadata.swift index 60434a6e6f..aa732be3f5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftAssetBriefMetadata.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftAssetBriefMetadata.swift @@ -46,5 +46,4 @@ class NftAssetBriefMetadata: Record { container[Columns.imageUrl] = imageUrl container[Columns.previewImageUrl] = previewImageUrl } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftAssetMetadata.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftAssetMetadata.swift index 8bde37f1ca..997315f48e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftAssetMetadata.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftAssetMetadata.swift @@ -44,7 +44,6 @@ struct NftAssetMetadata { let value: String let count: Int } - } struct ProviderLink { diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftAssetRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftAssetRecord.swift index fa1884d1a7..eb71374c8d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftAssetRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftAssetRecord.swift @@ -66,5 +66,4 @@ class NftAssetRecord: Record { container[Columns.lastSalePriceTokenQueryId] = lastSalePrice?.tokenQuery.id container[Columns.lastSalePriceValue] = lastSalePrice?.value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftCollectionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftCollectionRecord.swift index f9c563b78a..7a7ff694b9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftCollectionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftCollectionRecord.swift @@ -63,5 +63,4 @@ class NftCollectionRecord: Record { container[Columns.averagePrice30dTokenQueryId] = averagePrice30d?.tokenQuery.id container[Columns.averagePrice30dValue] = averagePrice30d?.value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftEventMetadata.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftEventMetadata.swift index 68855e80e3..2dca2e48a8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftEventMetadata.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftEventMetadata.swift @@ -10,7 +10,6 @@ struct NftEventMetadata { } extension NftEventMetadata { - enum EventType { case sale case transfer @@ -20,5 +19,4 @@ extension NftEventMetadata { case offer case offerCancel } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftKey.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftKey.swift index 8546cc8f69..3a653dc0cd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftKey.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftKey.swift @@ -9,8 +9,7 @@ struct NftKey: Hashable { hasher.combine(blockchainType) } - static func ==(lhs: NftKey, rhs: NftKey) -> Bool { + static func == (lhs: NftKey, rhs: NftKey) -> Bool { lhs.account == rhs.account && lhs.blockchainType == rhs.blockchainType } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftMetadataSyncRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftMetadataSyncRecord.swift index 63fd577813..6f4b7cc3a3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftMetadataSyncRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftMetadataSyncRecord.swift @@ -37,5 +37,4 @@ class NftMetadataSyncRecord: Record { container[Columns.accountId] = accountId container[Columns.lastSyncTimestamp] = lastSyncTimestamp } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftPriceRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftPriceRecord.swift index ea2b7e5dfd..cee148fe51 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftPriceRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftPriceRecord.swift @@ -11,7 +11,7 @@ struct NftPriceRecord { } init?(tokenQueryId: String?, value: Decimal?) { - if let tokenQueryId = tokenQueryId, let tokenQuery = TokenQuery(id: tokenQueryId), let value = value { + if let tokenQueryId, let tokenQuery = TokenQuery(id: tokenQueryId), let value { self.tokenQuery = tokenQuery self.value = value } else { diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/EvmNftRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/EvmNftRecord.swift index 5d05138902..643212bf12 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/EvmNftRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/EvmNftRecord.swift @@ -1,6 +1,6 @@ import Foundation -import NftKit import MarketKit +import NftKit class EvmNftRecord: NftRecord { let type: NftType @@ -20,5 +20,4 @@ class EvmNftRecord: NftRecord { override var nftUid: NftUid { .evm(blockchainType: blockchainType, contractAddress: contractAddress, tokenId: tokenId) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/NftRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/NftRecord.swift index 5fbcb25720..9baaf5560b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/NftRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftRecords/NftRecord.swift @@ -12,5 +12,4 @@ class NftRecord { var nftUid: NftUid { fatalError("Should be overridden") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/NftUid.swift b/UnstoppableWallet/UnstoppableWallet/Models/NftUid.swift index f2bb04b42b..23a3534f3d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/NftUid.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/NftUid.swift @@ -62,18 +62,16 @@ enum NftUid: Hashable { hasher.combine(uid) } - static func ==(lhs: NftUid, rhs: NftUid) -> Bool { + static func == (lhs: NftUid, rhs: NftUid) -> Bool { switch (lhs, rhs) { case let (.evm(lhsBlockchainType, lhsContractAddress, lhsTokenId), .evm(rhsBlockchainType, rhsContractAddress, rhsTokenId)): return lhsBlockchainType == rhsBlockchainType && lhsContractAddress == rhsContractAddress && lhsTokenId == rhsTokenId case let (.solana(lhsContractAddress, lhsTokenId), .solana(rhsContractAddress, rhsTokenId)): return lhsContractAddress == rhsContractAddress && lhsTokenId == rhsTokenId default: return false } } - } extension NftUid: DatabaseValueConvertible { - var databaseValue: DatabaseValue { uid.databaseValue } @@ -85,5 +83,4 @@ extension NftUid: DatabaseValueConvertible { return NftUid(uid: uid) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/PaymentRequestAddress.swift b/UnstoppableWallet/UnstoppableWallet/Models/PaymentRequestAddress.swift index 2237c59b88..e4bcccd7bc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/PaymentRequestAddress.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/PaymentRequestAddress.swift @@ -10,5 +10,4 @@ struct PaymentRequestAddress { self.amount = amount self.error = error } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/RestoreSettingRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/RestoreSettingRecord.swift index 5f1000e261..ea466443e5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/RestoreSettingRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/RestoreSettingRecord.swift @@ -38,5 +38,4 @@ class RestoreSettingRecord: Record { container[Columns.key] = key container[Columns.value] = value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/SendTransactionError.swift b/UnstoppableWallet/UnstoppableWallet/Models/SendTransactionError.swift index ed27cc233f..2fd5e2c4e0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/SendTransactionError.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/SendTransactionError.swift @@ -7,13 +7,11 @@ enum SendTransactionError: Error { } extension SendTransactionError: LocalizedError { - public var errorDescription: String? { switch self { case .wrongAmount: return "alert.wrong_amount".localized case .noFee: return "alert.no_fee".localized - case .invalidAddress: return "invalid address" // FIXME: localize or find the way to avoid this + case .invalidAddress: return "invalid address" // FIXME: localize or find the way to avoid this } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/SyncerState.swift b/UnstoppableWallet/UnstoppableWallet/Models/SyncerState.swift index ed3ff47818..75c4ea4be9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/SyncerState.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/SyncerState.swift @@ -30,5 +30,4 @@ class SyncerState: Record { container[Columns.key] = key container[Columns.value] = value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionDataSortMode.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionDataSortMode.swift index c294028ad9..302d580eb3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionDataSortMode.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionDataSortMode.swift @@ -9,5 +9,4 @@ enum TransactionDataSortMode: String, CaseIterable { var description: String { "btc_transaction_sort_mode.\(self).description".localized } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainIncomingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainIncomingTransactionRecord.swift index a0bcb56344..c2a6c9dda2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainIncomingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainIncomingTransactionRecord.swift @@ -15,5 +15,4 @@ class BinanceChainIncomingTransactionRecord: BinanceChainTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainOutgoingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainOutgoingTransactionRecord.swift index 9e0bd49883..ee93eafab4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainOutgoingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainOutgoingTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import BinanceChainKit +import Foundation import MarketKit class BinanceChainOutgoingTransactionRecord: BinanceChainTransactionRecord { @@ -18,5 +18,4 @@ class BinanceChainOutgoingTransactionRecord: BinanceChainTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainTransactionRecord.swift index 732c360161..275ec18c05 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/BinanceChain/BinanceChainTransactionRecord.swift @@ -10,15 +10,14 @@ class BinanceChainTransactionRecord: TransactionRecord { memo = transaction.memo super.init( - source: source, - uid: transaction.hash, - transactionHash: transaction.hash, - transactionIndex: 0, - blockHeight: transaction.blockHeight, - confirmationsThreshold: BinanceAdapter.confirmationsThreshold, - date: transaction.date, - failed: false + source: source, + uid: transaction.hash, + transactionHash: transaction.hash, + transactionIndex: 0, + blockHeight: transaction.blockHeight, + confirmationsThreshold: BinanceAdapter.confirmationsThreshold, + date: transaction.date, + failed: false ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinIncomingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinIncomingTransactionRecord.swift index 6589da5def..c474576001 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinIncomingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinIncomingTransactionRecord.swift @@ -7,29 +7,29 @@ class BitcoinIncomingTransactionRecord: BitcoinTransactionRecord { init(token: Token, source: TransactionSource, uid: String, transactionHash: String, transactionIndex: Int, blockHeight: Int?, confirmationsThreshold: Int?, date: Date, fee: Decimal?, failed: Bool, lockInfo: TransactionLockInfo?, conflictingHash: String?, showRawTransaction: Bool, - amount: Decimal, from: String?, memo: String? = nil) { + amount: Decimal, from: String?, memo: String? = nil) + { value = .coinValue(token: token, value: amount) self.from = from super.init( - source: source, - uid: uid, - transactionHash: transactionHash, - transactionIndex: transactionIndex, - blockHeight: blockHeight, - confirmationsThreshold: confirmationsThreshold, - date: date, - fee: fee.flatMap { .coinValue(token: token, value: $0) }, - failed: failed, - lockInfo: lockInfo, - conflictingHash: conflictingHash, - showRawTransaction: showRawTransaction, - memo: memo + source: source, + uid: uid, + transactionHash: transactionHash, + transactionIndex: transactionIndex, + blockHeight: blockHeight, + confirmationsThreshold: confirmationsThreshold, + date: date, + fee: fee.flatMap { .coinValue(token: token, value: $0) }, + failed: failed, + lockInfo: lockInfo, + conflictingHash: conflictingHash, + showRawTransaction: showRawTransaction, + memo: memo ) } override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinOutgoingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinOutgoingTransactionRecord.swift index 9e95230d0c..20bc1ed577 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinOutgoingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinOutgoingTransactionRecord.swift @@ -8,31 +8,30 @@ class BitcoinOutgoingTransactionRecord: BitcoinTransactionRecord { init(token: Token, source: TransactionSource, uid: String, transactionHash: String, transactionIndex: Int, blockHeight: Int?, confirmationsThreshold: Int?, date: Date, fee: Decimal?, failed: Bool, lockInfo: TransactionLockInfo?, conflictingHash: String?, showRawTransaction: Bool, - amount: Decimal, to: String?, sentToSelf: Bool, memo: String? = nil) { - + amount: Decimal, to: String?, sentToSelf: Bool, memo: String? = nil) + { value = .coinValue(token: token, value: Decimal(sign: .minus, exponent: amount.exponent, significand: amount.significand)) self.to = to self.sentToSelf = sentToSelf super.init( - source: source, - uid: uid, - transactionHash: transactionHash, - transactionIndex: transactionIndex, - blockHeight: blockHeight, - confirmationsThreshold: confirmationsThreshold, - date: date, - fee: fee.flatMap { .coinValue(token: token, value: $0) }, - failed: failed, - lockInfo: lockInfo, - conflictingHash: conflictingHash, - showRawTransaction: showRawTransaction, - memo: memo + source: source, + uid: uid, + transactionHash: transactionHash, + transactionIndex: transactionIndex, + blockHeight: blockHeight, + confirmationsThreshold: confirmationsThreshold, + date: date, + fee: fee.flatMap { .coinValue(token: token, value: $0) }, + failed: failed, + lockInfo: lockInfo, + conflictingHash: conflictingHash, + showRawTransaction: showRawTransaction, + memo: memo ) } override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinTransactionRecord.swift index 183f824fd9..b595a3f3c5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Bitcoin/BitcoinTransactionRecord.swift @@ -9,7 +9,8 @@ class BitcoinTransactionRecord: TransactionRecord { let memo: String? init(source: TransactionSource, uid: String, transactionHash: String, transactionIndex: Int, blockHeight: Int?, confirmationsThreshold: Int?, date: Date, fee: TransactionValue?, failed: Bool, - lockInfo: TransactionLockInfo?, conflictingHash: String?, showRawTransaction: Bool, memo: String?) { + lockInfo: TransactionLockInfo?, conflictingHash: String?, showRawTransaction: Bool, memo: String?) + { self.lockInfo = lockInfo self.fee = fee self.conflictingHash = conflictingHash @@ -17,31 +18,30 @@ class BitcoinTransactionRecord: TransactionRecord { self.memo = memo super.init( - source: source, - uid: uid, - transactionHash: transactionHash, - transactionIndex: transactionIndex, - blockHeight: blockHeight, - confirmationsThreshold: confirmationsThreshold, - date: date, - failed: failed + source: source, + uid: uid, + transactionHash: transactionHash, + transactionIndex: transactionIndex, + blockHeight: blockHeight, + confirmationsThreshold: confirmationsThreshold, + date: date, + failed: failed ) } override func lockState(lastBlockTimestamp: Int?) -> TransactionLockState? { - guard let lockInfo = lockInfo else { + guard let lockInfo else { return nil } var locked = true - if let lastBlockTimestamp = lastBlockTimestamp { + if let lastBlockTimestamp { locked = Double(lastBlockTimestamp) < lockInfo.lockedUntil.timeIntervalSince1970 } return TransactionLockState(locked: locked, date: lockInfo.lockedUntil) } - } struct TransactionLockState { @@ -50,9 +50,7 @@ struct TransactionLockState { } extension TransactionLockState: Equatable { - - public static func ==(lhs: TransactionLockState, rhs: TransactionLockState) -> Bool { + public static func == (lhs: TransactionLockState, rhs: TransactionLockState) -> Bool { lhs.locked == rhs.locked && lhs.date == rhs.date } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ApproveTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ApproveTransactionRecord.swift index 2bb7de23df..cbaa73a1ce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ApproveTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ApproveTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import MarketKit class ApproveTransactionRecord: EvmTransactionRecord { @@ -16,5 +16,4 @@ class ApproveTransactionRecord: EvmTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCallTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCallTransactionRecord.swift index 3f7d3919a1..a037fdaadd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCallTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCallTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import MarketKit class ContractCallTransactionRecord: EvmTransactionRecord { @@ -9,7 +9,8 @@ class ContractCallTransactionRecord: EvmTransactionRecord { let outgoingEvents: [TransferEvent] init(source: TransactionSource, transaction: Transaction, baseToken: Token, - contractAddress: String, method: String?, incomingEvents: [TransferEvent], outgoingEvents: [TransferEvent]) { + contractAddress: String, method: String?, incomingEvents: [TransferEvent], outgoingEvents: [TransferEvent]) + { self.contractAddress = contractAddress self.method = method self.incomingEvents = incomingEvents @@ -33,5 +34,4 @@ class ContractCallTransactionRecord: EvmTransactionRecord { return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCreationTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCreationTransactionRecord.swift index cbbd03daa4..06d3a47320 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCreationTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ContractCreationTransactionRecord.swift @@ -2,9 +2,7 @@ import EvmKit import MarketKit class ContractCreationTransactionRecord: EvmTransactionRecord { - init(source: TransactionSource, transaction: Transaction, baseToken: Token) { super.init(source: source, transaction: transaction, baseToken: baseToken, ownTransaction: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmIncomingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmIncomingTransactionRecord.swift index 4ae65c1841..ea4e8db903 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmIncomingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmIncomingTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import MarketKit class EvmIncomingTransactionRecord: EvmTransactionRecord { @@ -16,5 +16,4 @@ class EvmIncomingTransactionRecord: EvmTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmOutgoingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmOutgoingTransactionRecord.swift index 85ee49b541..a866d1c689 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmOutgoingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmOutgoingTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import MarketKit class EvmOutgoingTransactionRecord: EvmTransactionRecord { @@ -18,5 +18,4 @@ class EvmOutgoingTransactionRecord: EvmTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmTransactionRecord.swift index ebc12173c0..3a3263c5ad 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/EvmTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import MarketKit class EvmTransactionRecord: TransactionRecord { @@ -20,15 +20,15 @@ class EvmTransactionRecord: TransactionRecord { } super.init( - source: source, - uid: txHash, - transactionHash: txHash, - transactionIndex: transaction.transactionIndex ?? 0, - blockHeight: transaction.blockNumber, - confirmationsThreshold: BaseEvmAdapter.confirmationsThreshold, - date: Date(timeIntervalSince1970: Double(transaction.timestamp)), - failed: transaction.isFailed, - spam: spam + source: source, + uid: txHash, + transactionHash: txHash, + transactionIndex: transaction.transactionIndex ?? 0, + blockHeight: transaction.blockNumber, + confirmationsThreshold: BaseEvmAdapter.confirmationsThreshold, + date: Date(timeIntervalSince1970: Double(transaction.timestamp)), + failed: transaction.isFailed, + spam: spam ) } @@ -42,7 +42,7 @@ class EvmTransactionRecord: TransactionRecord { } func combined(incomingEvents: [TransferEvent], outgoingEvents: [TransferEvent]) -> ([TransactionValue], [TransactionValue]) { - let values = (incomingEvents + outgoingEvents).map { $0.value } + let values = (incomingEvents + outgoingEvents).map(\.value) var resultIncoming = [TransactionValue]() var resultOutgoing = [TransactionValue]() @@ -75,14 +75,11 @@ class EvmTransactionRecord: TransactionRecord { return (resultIncoming, resultOutgoing) } - } extension EvmTransactionRecord { - struct TransferEvent { let address: String let value: TransactionValue } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ExternalContractCallTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ExternalContractCallTransactionRecord.swift index aa06cdf894..26adf92b24 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ExternalContractCallTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/ExternalContractCallTransactionRecord.swift @@ -10,7 +10,7 @@ class ExternalContractCallTransactionRecord: EvmTransactionRecord { self.incomingEvents = incomingEvents self.outgoingEvents = outgoingEvents - let spam = TransactionRecord.isSpam(transactionValues: (incomingEvents + outgoingEvents).map { $0.value }) + let spam = TransactionRecord.isSpam(transactionValues: (incomingEvents + outgoingEvents).map(\.value)) super.init(source: source, transaction: transaction, baseToken: baseToken, ownTransaction: false, spam: spam) } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/SwapTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/SwapTransactionRecord.swift index bd6d0e2736..bb62483729 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/SwapTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/SwapTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import MarketKit class SwapTransactionRecord: EvmTransactionRecord { @@ -25,21 +25,18 @@ class SwapTransactionRecord: EvmTransactionRecord { var valueOut: TransactionValue? { amountOut?.value } - } extension SwapTransactionRecord { - enum Amount { case exact(value: TransactionValue) case extremum(value: TransactionValue) var value: TransactionValue { switch self { - case .exact(let value): return value - case .extremum(let value): return value + case let .exact(value): return value + case let .extremum(value): return value } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/UnknownSwapTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/UnknownSwapTransactionRecord.swift index 134bb8cc54..0f6a088315 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/UnknownSwapTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Evm/UnknownSwapTransactionRecord.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import MarketKit class UnknownSwapTransactionRecord: EvmTransactionRecord { @@ -14,5 +14,4 @@ class UnknownSwapTransactionRecord: EvmTransactionRecord { super.init(source: source, transaction: transaction, baseToken: baseToken, ownTransaction: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/TransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/TransactionRecord.swift index 57562d53ea..171b927210 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/TransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/TransactionRecord.swift @@ -26,7 +26,7 @@ class TransactionRecord { func status(lastBlockHeight: Int?) -> TransactionStatus { if failed { return .failed - } else if let blockHeight = blockHeight, let lastBlockHeight = lastBlockHeight { + } else if let blockHeight, let lastBlockHeight { let threshold = confirmationsThreshold ?? 1 let confirmations = lastBlockHeight - blockHeight + 1 @@ -135,10 +135,10 @@ extension TransactionRecord { } case let record as ContractCallTransactionRecord: - nftUids.formUnion(Set((record.incomingEvents + record.outgoingEvents).compactMap { $0.value.nftUid })) + nftUids.formUnion(Set((record.incomingEvents + record.outgoingEvents).compactMap(\.value.nftUid))) case let record as ExternalContractCallTransactionRecord: - nftUids.formUnion(Set((record.incomingEvents + record.outgoingEvents).compactMap { $0.value.nftUid })) + nftUids.formUnion(Set((record.incomingEvents + record.outgoingEvents).compactMap(\.value.nftUid))) default: () } @@ -147,7 +147,7 @@ extension TransactionRecord { } } -extension Array where Element == TransactionRecord { +extension [TransactionRecord] { var nftUids: Set { var nftUids = Set() diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronApproveTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronApproveTransactionRecord.swift index 340888de1b..062b53eb4d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronApproveTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronApproveTransactionRecord.swift @@ -1,6 +1,6 @@ import Foundation -import TronKit import MarketKit +import TronKit class TronApproveTransactionRecord: TronTransactionRecord { let spender: String @@ -16,5 +16,4 @@ class TronApproveTransactionRecord: TronTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronContractCallTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronContractCallTransactionRecord.swift index 7d9080b414..fe6f199deb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronContractCallTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronContractCallTransactionRecord.swift @@ -1,6 +1,6 @@ import Foundation -import TronKit import MarketKit +import TronKit class TronContractCallTransactionRecord: TronTransactionRecord { let contractAddress: String @@ -9,7 +9,8 @@ class TronContractCallTransactionRecord: TronTransactionRecord { let outgoingEvents: [TransferEvent] init(source: TransactionSource, transaction: Transaction, baseToken: Token, - contractAddress: String, method: String?, incomingEvents: [TransferEvent], outgoingEvents: [TransferEvent]) { + contractAddress: String, method: String?, incomingEvents: [TransferEvent], outgoingEvents: [TransferEvent]) + { self.contractAddress = contractAddress self.method = method self.incomingEvents = incomingEvents @@ -33,5 +34,4 @@ class TronContractCallTransactionRecord: TronTransactionRecord { return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronExternalContractCallTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronExternalContractCallTransactionRecord.swift index 494df3c231..3817d11f4d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronExternalContractCallTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronExternalContractCallTransactionRecord.swift @@ -10,7 +10,7 @@ class TronExternalContractCallTransactionRecord: TronTransactionRecord { self.incomingEvents = incomingEvents self.outgoingEvents = outgoingEvents - let spam = TransactionRecord.isSpam(transactionValues: (incomingEvents + outgoingEvents).map { $0.value }) + let spam = TransactionRecord.isSpam(transactionValues: (incomingEvents + outgoingEvents).map(\.value)) super.init(source: source, transaction: transaction, baseToken: baseToken, ownTransaction: false, spam: spam) } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronIncomingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronIncomingTransactionRecord.swift index 8e4c5174e7..aac07d8050 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronIncomingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronIncomingTransactionRecord.swift @@ -1,6 +1,6 @@ import Foundation -import TronKit import MarketKit +import TronKit class TronIncomingTransactionRecord: TronTransactionRecord { let from: String @@ -16,5 +16,4 @@ class TronIncomingTransactionRecord: TronTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronOutgoingTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronOutgoingTransactionRecord.swift index dd8fa21a51..ac8ee09b3e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronOutgoingTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronOutgoingTransactionRecord.swift @@ -1,6 +1,6 @@ import Foundation -import TronKit import MarketKit +import TronKit class TronOutgoingTransactionRecord: TronTransactionRecord { let to: String @@ -18,5 +18,4 @@ class TronOutgoingTransactionRecord: TronTransactionRecord { override var mainValue: TransactionValue? { value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronTransactionRecord.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronTransactionRecord.swift index 16d9bfc655..7c3f237f8f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronTransactionRecord.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionRecords/Tron/TronTransactionRecord.swift @@ -1,6 +1,6 @@ import Foundation -import TronKit import MarketKit +import TronKit class TronTransactionRecord: TransactionRecord { let transaction: Transaction @@ -36,15 +36,15 @@ class TronTransactionRecord: TransactionRecord { private func sameType(_ value: TransactionValue, _ value2: TransactionValue) -> Bool { switch (value, value2) { - case let (.coinValue(lhsToken, _), .coinValue(rhsToken, _)): return lhsToken == rhsToken - case let (.tokenValue(lhsTokenName, lhsTokenCode, lhsTokenDecimals, _), .tokenValue(rhsTokenName, rhsTokenCode, rhsTokenDecimals, _)): return lhsTokenName == rhsTokenName && lhsTokenCode == rhsTokenCode && lhsTokenDecimals == rhsTokenDecimals - case let (.nftValue(lhsNftUid, _, _, _), .nftValue(rhsNftUid, _, _, _)): return lhsNftUid == rhsNftUid - default: return false + case let (.coinValue(lhsToken, _), .coinValue(rhsToken, _)): return lhsToken == rhsToken + case let (.tokenValue(lhsTokenName, lhsTokenCode, lhsTokenDecimals, _), .tokenValue(rhsTokenName, rhsTokenCode, rhsTokenDecimals, _)): return lhsTokenName == rhsTokenName && lhsTokenCode == rhsTokenCode && lhsTokenDecimals == rhsTokenDecimals + case let (.nftValue(lhsNftUid, _, _, _), .nftValue(rhsNftUid, _, _, _)): return lhsNftUid == rhsNftUid + default: return false } } func combined(incomingEvents: [TransferEvent], outgoingEvents: [TransferEvent]) -> ([TransactionValue], [TransactionValue]) { - let values = (incomingEvents + outgoingEvents).map { $0.value } + let values = (incomingEvents + outgoingEvents).map(\.value) var resultIncoming = [TransactionValue]() var resultOutgoing = [TransactionValue]() @@ -58,14 +58,14 @@ class TronTransactionRecord: TransactionRecord { let resultValue: TransactionValue switch value { - case let .coinValue(token, _): - resultValue = .coinValue(token: token, value: totalValue) - case let .tokenValue(tokenName, tokenCode, tokenDecimals, _): - resultValue = .tokenValue(tokenName: tokenName, tokenCode: tokenCode, tokenDecimals: tokenDecimals, value: totalValue) - case let .nftValue(nftUid, _, tokenName, tokenSymbol): - resultValue = .nftValue(nftUid: nftUid, value: totalValue, tokenName: tokenName, tokenSymbol: tokenSymbol) - case let .rawValue(value): - resultValue = .rawValue(value: value) + case let .coinValue(token, _): + resultValue = .coinValue(token: token, value: totalValue) + case let .tokenValue(tokenName, tokenCode, tokenDecimals, _): + resultValue = .tokenValue(tokenName: tokenName, tokenCode: tokenCode, tokenDecimals: tokenDecimals, value: totalValue) + case let .nftValue(nftUid, _, tokenName, tokenSymbol): + resultValue = .nftValue(nftUid: nftUid, value: totalValue, tokenName: tokenName, tokenSymbol: tokenSymbol) + case let .rawValue(value): + resultValue = .rawValue(value: value) } if totalValue > 0 { @@ -78,7 +78,7 @@ class TronTransactionRecord: TransactionRecord { return (resultIncoming, resultOutgoing) } - override func status(lastBlockHeight: Int?) -> TransactionStatus { + override func status(lastBlockHeight _: Int?) -> TransactionStatus { if failed { return .failed } @@ -89,14 +89,11 @@ class TronTransactionRecord: TransactionRecord { return .pending } - } extension TronTransactionRecord { - struct TransferEvent { let address: String let value: TransactionValue } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/TransactionValue.swift b/UnstoppableWallet/UnstoppableWallet/Models/TransactionValue.swift index 02d58582f7..f02866b60d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/TransactionValue.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/TransactionValue.swift @@ -1,6 +1,6 @@ +import BigInt import Foundation import MarketKit -import BigInt enum TransactionValue { case coinValue(token: Token, value: Decimal) @@ -10,45 +10,45 @@ enum TransactionValue { var fullName: String { switch self { - case .coinValue(let token, _): return token.coin.name - case .tokenValue(let tokenName, _, _, _): return tokenName - case .nftValue(let nftUid, _, let tokenName, _): return tokenName.map { "\($0) #\(nftUid.tokenId)" } ?? "#\(nftUid.tokenId)" + case let .coinValue(token, _): return token.coin.name + case let .tokenValue(tokenName, _, _, _): return tokenName + case let .nftValue(nftUid, _, tokenName, _): return tokenName.map { "\($0) #\(nftUid.tokenId)" } ?? "#\(nftUid.tokenId)" case .rawValue: return "" } } var coinCode: String { switch self { - case .coinValue(let token, _): return token.coin.code - case .tokenValue(_, let tokenCode, _, _): return tokenCode - case .nftValue(_, _, _, let tokenSymbol): return tokenSymbol ?? "NFT" + case let .coinValue(token, _): return token.coin.code + case let .tokenValue(_, tokenCode, _, _): return tokenCode + case let .nftValue(_, _, _, tokenSymbol): return tokenSymbol ?? "NFT" case .rawValue: return "" } } var coin: Coin? { switch self { - case .coinValue(let token, _): return token.coin + case let .coinValue(token, _): return token.coin default: return nil } } var token: Token? { switch self { - case .coinValue(let token, _): return token + case let .coinValue(token, _): return token default: return nil } } var tokenProtocol: TokenProtocol? { switch self { - case .coinValue(let token, _): return token.type.tokenProtocol + case let .coinValue(token, _): return token.type.tokenProtocol case .tokenValue: return .eip20 case .nftValue: return nil case .rawValue: return nil } } - + var nftUid: NftUid? { switch self { case let .nftValue(nftUid, _, _, _): return nftUid @@ -58,26 +58,26 @@ enum TransactionValue { var decimalValue: Decimal? { switch self { - case .coinValue(_, let value): return value - case .tokenValue(_, _, _, let value): return value - case .nftValue(_, let value, _, _): return value + case let .coinValue(_, value): return value + case let .tokenValue(_, _, _, value): return value + case let .nftValue(_, value, _, _): return value case .rawValue: return nil } } var zeroValue: Bool { switch self { - case .coinValue(_, let value): return value == 0 - case .tokenValue(_, _, _, let value): return value == 0 - case .nftValue(_, let value, _, _): return value == 0 - case .rawValue(let value): return value == 0 + case let .coinValue(_, value): return value == 0 + case let .tokenValue(_, _, _, value): return value == 0 + case let .nftValue(_, value, _, _): return value == 0 + case let .rawValue(value): return value == 0 } } public var isMaxValue: Bool { switch self { - case .coinValue(let token, let value): return value.isMaxValue(decimals: token.decimals) - case .tokenValue(_, _, let tokenDecimals, let value): return value.isMaxValue(decimals: tokenDecimals) + case let .coinValue(token, value): return value.isMaxValue(decimals: token.decimals) + case let .tokenValue(_, _, tokenDecimals, value): return value.isMaxValue(decimals: tokenDecimals) default: return false } } @@ -107,19 +107,16 @@ enum TransactionValue { return nil } } - } extension TransactionValue: Equatable { - - static func ==(lhs: TransactionValue, rhs: TransactionValue) -> Bool { + static func == (lhs: TransactionValue, rhs: TransactionValue) -> Bool { switch (lhs, rhs) { - case (.coinValue(let lhsToken, let lhsValue), .coinValue(let rhsToken, let rhsValue)): return lhsToken == rhsToken && lhsValue == rhsValue - case (.tokenValue(let lhsTokenName, let lhsTokenCode, let lhsTokenDecimals, let lhsValue), .tokenValue(let rhsTokenName, let rhsTokenCode, let rhsTokenDecimals, let rhsValue)): return lhsTokenName == rhsTokenName && lhsTokenCode == rhsTokenCode && lhsTokenDecimals == rhsTokenDecimals && lhsValue == rhsValue - case (.nftValue(let lhsNftUid, let lhsValue, _, _), .nftValue(let rhsNftUid, let rhsValue, _, _)): return lhsNftUid == rhsNftUid && lhsValue == rhsValue - case (.rawValue(let lhsValue), .rawValue(let rhsValue)): return lhsValue == rhsValue + case let (.coinValue(lhsToken, lhsValue), .coinValue(rhsToken, rhsValue)): return lhsToken == rhsToken && lhsValue == rhsValue + case let (.tokenValue(lhsTokenName, lhsTokenCode, lhsTokenDecimals, lhsValue), .tokenValue(rhsTokenName, rhsTokenCode, rhsTokenDecimals, rhsValue)): return lhsTokenName == rhsTokenName && lhsTokenCode == rhsTokenCode && lhsTokenDecimals == rhsTokenDecimals && lhsValue == rhsValue + case let (.nftValue(lhsNftUid, lhsValue, _, _), .nftValue(rhsNftUid, rhsValue, _, _)): return lhsNftUid == rhsNftUid && lhsValue == rhsValue + case let (.rawValue(lhsValue), .rawValue(rhsValue)): return lhsValue == rhsValue default: return false } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/Wallet.swift b/UnstoppableWallet/UnstoppableWallet/Models/Wallet.swift index a29f8affe1..6595d6b908 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/Wallet.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/Wallet.swift @@ -23,16 +23,14 @@ struct Wallet { var transactionSource: TransactionSource { TransactionSource( - blockchainType: token.blockchainType, - meta: token.type.meta + blockchainType: token.blockchainType, + meta: token.type.meta ) } - } extension Wallet: Hashable { - - public static func ==(lhs: Wallet, rhs: Wallet) -> Bool { + public static func == (lhs: Wallet, rhs: Wallet) -> Bool { lhs.token == rhs.token && lhs.account == rhs.account } @@ -40,5 +38,4 @@ extension Wallet: Hashable { hasher.combine(token) hasher.combine(account) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Models/WalletConnectSession.swift b/UnstoppableWallet/UnstoppableWallet/Models/WalletConnectSession.swift index c74986c4e8..f8491fe10f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Models/WalletConnectSession.swift +++ b/UnstoppableWallet/UnstoppableWallet/Models/WalletConnectSession.swift @@ -17,5 +17,4 @@ class WalletConnectSession: Codable, FetchableRecord, PersistableRecord, TableRe static let accountId = Column(CodingKeys.accountId) static let topic = Column(CodingKeys.topic) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionModule.swift index 7ab6ef92d8..dc4b5a6799 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionModule.swift @@ -1,14 +1,13 @@ import Foundation -import UIKit import ThemeKit +import UIKit struct ActivateSubscriptionModule { - static func viewController() -> UIViewController { let service = ActivateSubscriptionService( - marketKit: App.shared.marketKit, - subscriptionManager: App.shared.subscriptionManager, - accountManager: App.shared.accountManager + marketKit: App.shared.marketKit, + subscriptionManager: App.shared.subscriptionManager, + accountManager: App.shared.accountManager ) let viewModel = ActivateSubscriptionViewModel(service: service) @@ -16,5 +15,4 @@ struct ActivateSubscriptionModule { return ThemeNavigationController(rootViewController: viewController) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionService.swift index c05a174899..bdd25c0d77 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionService.swift @@ -1,9 +1,9 @@ -import Foundation import Combine import EvmKit -import MarketKit -import HsToolKit +import Foundation import HsExtensions +import HsToolKit +import MarketKit class ActivateSubscriptionService { private let marketKit: MarketKit.Kit @@ -41,7 +41,7 @@ class ActivateSubscriptionService { state = .loading - let addresses = addressItems.map { $0.address.hex } + let addresses = addressItems.map(\.address.hex) Task { [weak self, marketKit] in do { @@ -79,11 +79,9 @@ class ActivateSubscriptionService { } }.store(in: &tasks) } - } extension ActivateSubscriptionService { - var activatedPublisher: AnyPublisher { activatedSubject.eraseToAnyPublisher() } @@ -118,11 +116,9 @@ extension ActivateSubscriptionService { } }.store(in: &tasks) } - } extension ActivateSubscriptionService { - private struct AddressItem { let account: Account let address: EvmKit.Address @@ -139,5 +135,4 @@ extension ActivateSubscriptionService { case ready case activating } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewController.swift index 3ce8d930e6..71bd3da396 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewController.swift @@ -1,11 +1,11 @@ -import Foundation import Combine -import UIKit -import SnapKit -import ThemeKit import ComponentKit -import SectionsTableView +import Foundation import HUD +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class ActivateSubscriptionViewController: ThemeViewController { private let viewModel: ActivateSubscriptionViewModel @@ -29,7 +29,8 @@ class ActivateSubscriptionViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -91,62 +92,62 @@ class ActivateSubscriptionViewController: ThemeViewController { rejectButton.addTarget(self, action: #selector(onTapReject), for: .touchUpInside) viewModel.$spinnerVisible - .receive(on: DispatchQueue.main) - .sink { [weak self] visible in self?.spinner.isHidden = !visible } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] visible in self?.spinner.isHidden = !visible } + .store(in: &cancellables) viewModel.$errorVisible - .receive(on: DispatchQueue.main) - .sink { [weak self] visible in self?.errorView.isHidden = !visible } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] visible in self?.errorView.isHidden = !visible } + .store(in: &cancellables) viewModel.$noSubscriptionsVisible - .receive(on: DispatchQueue.main) - .sink { [weak self] visible in self?.noSubscriptionsView.isHidden = !visible } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] visible in self?.noSubscriptionsView.isHidden = !visible } + .store(in: &cancellables) viewModel.$viewItem - .receive(on: DispatchQueue.main) - .sink { [weak self] viewItem in - if let viewItem { - self?.viewItem = viewItem - self?.tableView.reload() - self?.tableView.isHidden = false - self?.buttonsHolder.isHidden = false - } else { - self?.tableView.isHidden = true - self?.buttonsHolder.isHidden = true - } + .receive(on: DispatchQueue.main) + .sink { [weak self] viewItem in + if let viewItem { + self?.viewItem = viewItem + self?.tableView.reload() + self?.tableView.isHidden = false + self?.buttonsHolder.isHidden = false + } else { + self?.tableView.isHidden = true + self?.buttonsHolder.isHidden = true } - .store(in: &cancellables) + } + .store(in: &cancellables) viewModel.$signVisible - .receive(on: DispatchQueue.main) - .sink { [weak self] visible in self?.signButton.isHidden = !visible } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] visible in self?.signButton.isHidden = !visible } + .store(in: &cancellables) viewModel.$activatingVisible - .receive(on: DispatchQueue.main) - .sink { [weak self] visible in self?.activatingButton.isHidden = !visible } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] visible in self?.activatingButton.isHidden = !visible } + .store(in: &cancellables) viewModel.$rejectEnabled - .receive(on: DispatchQueue.main) - .sink { [weak self] enabled in self?.rejectButton.isEnabled = enabled } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] enabled in self?.rejectButton.isEnabled = enabled } + .store(in: &cancellables) viewModel.errorPublisher - .receive(on: DispatchQueue.main) - .sink { text in HudHelper.instance.showErrorBanner(title: text) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { text in HudHelper.instance.showErrorBanner(title: text) } + .store(in: &cancellables) viewModel.finishPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - HudHelper.instance.show(banner: .success(string: "activate_subscription.activated".localized)) - self?.dismiss(animated: true) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + HudHelper.instance.show(banner: .success(string: "activate_subscription.activated".localized)) + self?.dismiss(animated: true) + } + .store(in: &cancellables) } @objc private func onTapSign() { @@ -164,11 +165,9 @@ class ActivateSubscriptionViewController: ThemeViewController { @objc private func onTapClose() { dismiss(animated: true) } - } extension ActivateSubscriptionViewController: SectionsDataSource { - private func addressRow(tableView: UITableView, value: String) -> RowProtocol { let backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence let title = "activate_subscription.address".localized @@ -176,48 +175,48 @@ extension ActivateSubscriptionViewController: SectionsDataSource { let valueFont: UIFont = .subhead1 return CellBuilderNew.row( - rootElement: .hStack([ - .text { component in - component.font = titleFont - component.textColor = .themeGray - component.text = title - component.setContentCompressionResistancePriority(.required, for: .horizontal) - }, - .text { component in - component.font = valueFont - component.textColor = .themeLeah - component.text = value - component.textAlignment = .right - component.numberOfLines = 0 - }, - .margin8, - .secondaryCircleButton { component in - component.button.set(image: UIImage(named: "copy_20")) - component.onTap = { - CopyHelper.copyAndNotify(value: value) - } + rootElement: .hStack([ + .text { component in + component.font = titleFont + component.textColor = .themeGray + component.text = title + component.setContentCompressionResistancePriority(.required, for: .horizontal) + }, + .text { component in + component.font = valueFont + component.textColor = .themeLeah + component.text = value + component.textAlignment = .right + component.numberOfLines = 0 + }, + .margin8, + .secondaryCircleButton { component in + component.button.set(image: UIImage(named: "copy_20")) + component.onTap = { + CopyHelper.copyAndNotify(value: value) } - ]), - tableView: tableView, - id: "address", - hash: value, - dynamicHeight: { containerWidth in - CellBuilderNew.height( - containerWidth: containerWidth, - backgroundStyle: backgroundStyle, - text: value, - font: valueFont, - elements: [ - .fixed(width: TextComponent.width(font: titleFont, text: title)), - .multiline, - .margin8, - .fixed(width: SecondaryCircleButton.size) - ] - ) }, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isLast: true) - } + ]), + tableView: tableView, + id: "address", + hash: value, + dynamicHeight: { containerWidth in + CellBuilderNew.height( + containerWidth: containerWidth, + backgroundStyle: backgroundStyle, + text: value, + font: valueFont, + elements: [ + .fixed(width: TextComponent.width(font: titleFont, text: title)), + .multiline, + .margin8, + .fixed(width: SecondaryCircleButton.size), + ] + ) + }, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isLast: true) + } ) } @@ -228,28 +227,27 @@ extension ActivateSubscriptionViewController: SectionsDataSource { return [ Section( - id: "main", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin24), - rows: [ - tableView.universalRow48( - id: "wallet-name", - title: .subhead2("activate_subscription.wallet".localized), - value: .subhead1(viewItem.walletName), - isFirst: true - ), - addressRow(tableView: tableView, value: viewItem.address) - ] + id: "main", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin24), + rows: [ + tableView.universalRow48( + id: "wallet-name", + title: .subhead2("activate_subscription.wallet".localized), + value: .subhead1(viewItem.walletName), + isFirst: true + ), + addressRow(tableView: tableView, value: viewItem.address), + ] ), Section( - id: "message", - headerState: tableView.sectionHeader(text: "activate_subscription.message".localized), - footerState: .margin(height: .margin32), - rows: [ - tableView.messageRow(text: viewItem.message) - ] - ) + id: "message", + headerState: tableView.sectionHeader(text: "activate_subscription.message".localized), + footerState: .margin(height: .margin32), + rows: [ + tableView.messageRow(text: viewItem.message), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewModel.swift index ca47af8611..8f161a1022 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ActivateSubscription/ActivateSubscriptionViewModel.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation class ActivateSubscriptionViewModel { private let service: ActivateSubscriptionService @@ -18,12 +18,12 @@ class ActivateSubscriptionViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) service.$activationState - .sink { [weak self] in self?.sync(activationState: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(activationState: $0) } + .store(in: &cancellables) sync(state: service.state) sync(activationState: service.activationState) @@ -66,15 +66,13 @@ class ActivateSubscriptionViewModel { rejectEnabled = false } } - } extension ActivateSubscriptionViewModel { - var errorPublisher: AnyPublisher { service.activationErrorPublisher - .map { _ in "activate_subscription.failed_to_activate".localized } - .eraseToAnyPublisher() + .map { _ in "activate_subscription.failed_to_activate".localized } + .eraseToAnyPublisher() } var finishPublisher: AnyPublisher { @@ -88,15 +86,12 @@ extension ActivateSubscriptionViewModel { func onTapSign() { service.sign() } - } extension ActivateSubscriptionViewModel { - struct ViewItem { let walletName: String let address: String let message: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddBep2TokenBlockchainService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddBep2TokenBlockchainService.swift index 6f364e6fe8..86591c39f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddBep2TokenBlockchainService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddBep2TokenBlockchainService.swift @@ -1,9 +1,9 @@ +import Alamofire import Foundation -import RxSwift import HsToolKit -import Alamofire -import ObjectMapper import MarketKit +import ObjectMapper +import RxSwift class AddBep2TokenBlockchainService { private let blockchain: Blockchain @@ -13,11 +13,9 @@ class AddBep2TokenBlockchainService { self.blockchain = blockchain self.networkManager = networkManager } - } extension AddBep2TokenBlockchainService: IAddTokenBlockchainService { - var placeholder: String { "add_token.input_placeholder.bep2_symbol".localized } @@ -40,7 +38,7 @@ extension AddBep2TokenBlockchainService: IAddTokenBlockchainService { let reference = reference.uppercased() let parameters: Parameters = [ - "limit": 1000 + "limit": 1000, ] let url = "https://dex.binance.org/api/v1/tokens" @@ -49,26 +47,24 @@ extension AddBep2TokenBlockchainService: IAddTokenBlockchainService { let blockchain = blockchain return networkManager.single(request: request) - .flatMap { (bep2Tokens: [Bep2Token]) -> Single in - guard let bep2Token = bep2Tokens.first(where: { $0.symbol == reference }) else { - return Single.error(TokenError.notFound) - } - - let token = Token( - coin: Coin(uid: tokenQuery.customCoinUid, name: bep2Token.name, code: bep2Token.originalSymbol), - blockchain: blockchain, - type: tokenQuery.tokenType, - decimals: 0 - ) - - return Single.just(token) + .flatMap { (bep2Tokens: [Bep2Token]) -> Single in + guard let bep2Token = bep2Tokens.first(where: { $0.symbol == reference }) else { + return Single.error(TokenError.notFound) } - } + let token = Token( + coin: Coin(uid: tokenQuery.customCoinUid, name: bep2Token.name, code: bep2Token.originalSymbol), + blockchain: blockchain, + type: tokenQuery.tokenType, + decimals: 0 + ) + + return Single.just(token) + } + } } extension AddBep2TokenBlockchainService { - struct Bep2Token: ImmutableMappable { let name: String let originalSymbol: String @@ -92,5 +88,4 @@ extension AddBep2TokenBlockchainService { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddEvmTokenBlockchainService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddEvmTokenBlockchainService.swift index e14c54ae37..6a2e2be5bc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddEvmTokenBlockchainService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddEvmTokenBlockchainService.swift @@ -1,9 +1,9 @@ -import Foundation -import RxSwift -import EvmKit import Eip20Kit +import EvmKit +import Foundation import HsToolKit import MarketKit +import RxSwift class AddEvmTokenBlockchainService { private let blockchain: Blockchain @@ -20,11 +20,9 @@ class AddEvmTokenBlockchainService { self.rpcSource = rpcSource } - } extension AddEvmTokenBlockchainService: IAddTokenBlockchainService { - var placeholder: String { "add_token.input_placeholder.contract_address".localized } @@ -50,23 +48,21 @@ extension AddEvmTokenBlockchainService: IAddTokenBlockchainService { let blockchain = blockchain return Eip20Kit.Kit.tokenInfoSingle(networkManager: networkManager, rpcSource: rpcSource, contractAddress: address) - .map { tokenInfo in - Token( - coin: Coin(uid: tokenQuery.customCoinUid, name: tokenInfo.name, code: tokenInfo.symbol), - blockchain: blockchain, - type: tokenQuery.tokenType, - decimals: tokenInfo.decimals - ) - } - .catchError { _ in - Single.error(TokenError.notFound(blockchainName: blockchain.name)) - } + .map { tokenInfo in + Token( + coin: Coin(uid: tokenQuery.customCoinUid, name: tokenInfo.name, code: tokenInfo.symbol), + blockchain: blockchain, + type: tokenQuery.tokenType, + decimals: tokenInfo.decimals + ) + } + .catchError { _ in + Single.error(TokenError.notFound(blockchainName: blockchain.name)) + } } - } extension AddEvmTokenBlockchainService { - enum TokenError: LocalizedError { case invalidAddress case notFound(blockchainName: String) @@ -74,9 +70,8 @@ extension AddEvmTokenBlockchainService { var errorDescription: String? { switch self { case .invalidAddress: return "add_token.invalid_contract_address".localized - case .notFound(let blockchainName): return "add_token.contract_address_not_found".localized(blockchainName) + case let .notFound(blockchainName): return "add_token.contract_address_not_found".localized(blockchainName) } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenModule.swift index 5eaf644e2c..c1034ad91a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenModule.swift @@ -1,11 +1,10 @@ -import Foundation -import UIKit -import ThemeKit import EvmKit +import Foundation import MarketKit +import ThemeKit +import UIKit struct AddTokenModule { - static func viewController() -> UIViewController? { guard let account = App.shared.accountManager.activeAccount else { return nil @@ -15,20 +14,19 @@ struct AddTokenModule { for blockchain in App.shared.evmBlockchainManager.allBlockchains { if let service: IAddTokenBlockchainService = AddEvmTokenBlockchainService( - blockchain: blockchain, - networkManager: App.shared.networkManager, - evmSyncSourceManager: App.shared.evmSyncSourceManager + blockchain: blockchain, + networkManager: App.shared.networkManager, + evmSyncSourceManager: App.shared.evmSyncSourceManager ) { let item = Item(blockchain: blockchain, service: service) items.append(item) } - } if let blockchain = try? App.shared.marketKit.blockchain(uid: BlockchainType.binanceChain.uid), blockchain.type.supports(accountType: account.type) { let service: IAddTokenBlockchainService = AddBep2TokenBlockchainService( - blockchain: blockchain, - networkManager: App.shared.networkManager + blockchain: blockchain, + networkManager: App.shared.networkManager ) let item = Item(blockchain: blockchain, service: service) items.append(item) @@ -51,14 +49,11 @@ struct AddTokenModule { return ThemeNavigationController(rootViewController: viewController) } - } extension AddTokenModule { - struct Item { let blockchain: Blockchain let service: IAddTokenBlockchainService } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenService.swift index 35b8957378..2d50b3022d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenService.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay import HsToolKit import MarketKit +import RxRelay +import RxSwift protocol IAddTokenBlockchainService { var placeholder: String { get } @@ -74,22 +74,20 @@ class AddTokenService { state = .loading service.tokenSingle(reference: reference) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe( - onSuccess: { [weak self] token in - self?.state = .fetched(token: token) - }, - onError: { [weak self] error in - self?.state = .failed(error: error) - } - ) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe( + onSuccess: { [weak self] token in + self?.state = .fetched(token: token) + }, + onError: { [weak self] error in + self?.state = .failed(error: error) + } + ) + .disposed(by: disposeBag) } - } extension AddTokenService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -116,18 +114,16 @@ extension AddTokenService { } func save() { - guard case .fetched(let token) = state else { + guard case let .fetched(token) = state else { return } let wallet = Wallet(token: token, account: account) walletManager.save(wallets: [wallet]) } - } extension AddTokenService { - enum State { case idle case loading @@ -150,5 +146,4 @@ extension AddTokenService { placeholder = item.service.placeholder } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewController.swift index 1524b3130a..2ac82b0017 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewController.swift @@ -1,11 +1,11 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift import RxCocoa -import ComponentKit +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class AddTokenViewController: ThemeViewController { private let viewModel: AddTokenViewModel @@ -29,7 +29,8 @@ class AddTokenViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -127,94 +128,91 @@ class AddTokenViewController: ThemeViewController { private func openBlockchainSelector() { let viewController = SelectorModule.singleSelectorViewController( - title: "add_token.blockchain".localized, - viewItems: viewModel.blockchainViewItems, - onSelect: { [weak self] index in - self?.viewModel.onSelectBlockchain(index: index) - } + title: "add_token.blockchain".localized, + viewItems: viewModel.blockchainViewItems, + onSelect: { [weak self] index in + self?.viewModel.onSelectBlockchain(index: index) + } ) present(viewController, animated: true) } - } extension AddTokenViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections: [SectionProtocol] = [ Section( - id: "blockchain", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "blockchain", - image: .local(UIImage(named: "blocks_24")?.withTintColor(.themeGray)), - title: .body("add_token.blockchain".localized), - value: .subhead1(blockchain, color: .themeGray), - accessoryType: .dropdown, - hash: blockchain, - autoDeselect: true, - isFirst: true, - isLast: true, - action: { [weak self] in - self?.openBlockchainSelector() - } - ) - ] + id: "blockchain", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( + id: "blockchain", + image: .local(UIImage(named: "blocks_24")?.withTintColor(.themeGray)), + title: .body("add_token.blockchain".localized), + value: .subhead1(blockchain, color: .themeGray), + accessoryType: .dropdown, + hash: blockchain, + autoDeselect: true, + isFirst: true, + isLast: true, + action: { [weak self] in + self?.openBlockchainSelector() + } + ), + ] ), Section( - id: "input", + id: "input", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: inputCell, + id: "input", + dynamicHeight: { [weak self] width in + self?.inputCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: inputCautionCell, + id: "input-caution", + dynamicHeight: { [weak self] width in + self?.inputCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), + ] + + if let viewItem { + sections.append( + Section( + id: "token-info", footerState: .margin(height: .margin32), rows: [ - StaticRow( - cell: inputCell, - id: "input", - dynamicHeight: { [weak self] width in - self?.inputCell.height(containerWidth: width) ?? 0 - } + tableView.universalRow48( + id: "coin-name", + title: .subhead2("add_token.coin_name".localized), + value: .subhead1(viewItem.name), + isFirst: true + ), + tableView.universalRow48( + id: "coin-name", + title: .subhead2("add_token.symbol".localized), + value: .subhead1(viewItem.code) + ), + tableView.universalRow48( + id: "coin-name", + title: .subhead2("add_token.decimals".localized), + value: .subhead1(viewItem.decimals), + isLast: true ), - StaticRow( - cell: inputCautionCell, - id: "input-caution", - dynamicHeight: { [weak self] width in - self?.inputCautionCell.height(containerWidth: width) ?? 0 - } - ) ] - ) - ] - - if let viewItem = viewItem { - sections.append( - Section( - id: "token-info", - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "coin-name", - title: .subhead2("add_token.coin_name".localized), - value: .subhead1(viewItem.name), - isFirst: true - ), - tableView.universalRow48( - id: "coin-name", - title: .subhead2("add_token.symbol".localized), - value: .subhead1(viewItem.code) - ), - tableView.universalRow48( - id: "coin-name", - title: .subhead2("add_token.decimals".localized), - value: .subhead1(viewItem.decimals), - isLast: true - ) - ] - ) + ) ) } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewModel.swift index c1dc8f0c1d..2824cb41ad 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTokenViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class AddTokenViewModel { private let service: AddTokenService @@ -42,17 +42,17 @@ class AddTokenViewModel { viewItemRelay.accept(nil) buttonEnabledRelay.accept(false) cautionRelay.accept(nil) - case .alreadyExists(let token): + case let .alreadyExists(token): loadingRelay.accept(false) viewItemRelay.accept(viewItem(token: token)) buttonEnabledRelay.accept(false) cautionRelay.accept(Caution(text: "add_token.already_added".localized, type: .warning)) - case .fetched(let token): + case let .fetched(token): loadingRelay.accept(false) viewItemRelay.accept(viewItem(token: token)) buttonEnabledRelay.accept(true) cautionRelay.accept(nil) - case .failed(let error): + case let .failed(error): loadingRelay.accept(false) viewItemRelay.accept(nil) buttonEnabledRelay.accept(false) @@ -62,16 +62,14 @@ class AddTokenViewModel { private func viewItem(token: Token) -> ViewItem { ViewItem( - name: token.coin.name, - code: token.coin.code, - decimals: String(token.decimals) + name: token.coin.name, + code: token.coin.code, + decimals: String(token.decimals) ) } - } extension AddTokenViewModel { - var blockchainDriver: Driver { blockchainRelay.asDriver() } @@ -103,9 +101,9 @@ extension AddTokenViewModel { var blockchainViewItems: [SelectorModule.ViewItem] { service.blockchainItems.map { item in SelectorModule.ViewItem( - image: .url(item.blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), - title: item.blockchain.name, - selected: item.current + image: .url(item.blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), + title: item.blockchain.name, + selected: item.current ) } } @@ -122,15 +120,12 @@ extension AddTokenViewModel { service.save() finishRelay.accept(()) } - } extension AddTokenViewModel { - struct ViewItem { let name: String let code: String let decimals: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTronTokenBlockchainService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTronTokenBlockchainService.swift index e455612c76..86de7d7b5c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTronTokenBlockchainService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/AddToken/AddTronTokenBlockchainService.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import TronKit import HsToolKit import MarketKit +import RxSwift +import TronKit class AddTronTokenBlockchainService { private let blockchain: Blockchain @@ -14,11 +14,9 @@ class AddTronTokenBlockchainService { self.networkManager = networkManager self.network = network } - } extension AddTronTokenBlockchainService: IAddTokenBlockchainService { - var placeholder: String { "add_token.input_placeholder.contract_address".localized } @@ -75,11 +73,9 @@ extension AddTronTokenBlockchainService: IAddTokenBlockchainService { } } } - } extension AddTronTokenBlockchainService { - enum TokenError: LocalizedError { case disposableError case invalidAddress @@ -87,11 +83,10 @@ extension AddTronTokenBlockchainService { var errorDescription: String? { switch self { - case .disposableError: return "" - case .invalidAddress: return "add_token.invalid_contract_address".localized - case .notFound(let blockchainName): return "add_token.contract_address_not_found".localized(blockchainName) + case .disposableError: return "" + case .invalidAddress: return "add_token.invalid_contract_address".localized + case let .notFound(blockchainName): return "add_token.contract_address_not_found".localized(blockchainName) } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertModule.swift index 9a84258c05..2025c6748d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertModule.swift @@ -23,5 +23,4 @@ struct AlertViewItem { self.selected = selected self.disabled = disabled } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertPresenter.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertPresenter.swift index 31d60afe73..b2ab9c6d82 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertPresenter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertPresenter.swift @@ -2,29 +2,26 @@ class AlertPresenter { weak var view: IAlertView? private let viewItems: [AlertViewItem] - private let onSelect: (Int) -> () + private let onSelect: (Int) -> Void let afterClose: Bool private let router: IAlertRouter - init(viewItems: [AlertViewItem], onSelect: @escaping (Int) -> (), router: IAlertRouter, afterClose: Bool) { + init(viewItems: [AlertViewItem], onSelect: @escaping (Int) -> Void, router: IAlertRouter, afterClose: Bool) { self.viewItems = viewItems self.onSelect = onSelect self.router = router self.afterClose = afterClose } - } extension AlertPresenter: IAlertViewDelegate { - func onLoad() { view?.set(viewItems: viewItems) } func onTapViewItem(index: Int) { - if afterClose { router.close { [weak self] in self?.onSelect(index) @@ -34,5 +31,4 @@ extension AlertPresenter: IAlertViewDelegate { router.close(completion: nil) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertRouter.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertRouter.swift index 83a5723d13..31c2201726 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertRouter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertRouter.swift @@ -5,18 +5,15 @@ class AlertRouter { } extension AlertRouter: IAlertRouter { - func close(completion: (() -> Void)? = nil) { DispatchQueue.main.async { [weak self] in self?.viewController?.dismiss(animated: true, completion: completion) } } - } extension AlertRouter { - - static func module(title: String, viewItems: [AlertViewItem], afterClose: Bool = false, onSelect: @escaping (Int) -> ()) -> UIViewController { + static func module(title: String, viewItems: [AlertViewItem], afterClose: Bool = false, onSelect: @escaping (Int) -> Void) -> UIViewController { let router = AlertRouter() let presenter = AlertPresenter(viewItems: viewItems, onSelect: onSelect, router: router, afterClose: afterClose) let viewController = AlertViewController(alertTitle: title, delegate: presenter) @@ -26,5 +23,4 @@ extension AlertRouter { return viewController.toAlert } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewController.swift index 757c9ca666..e6afc8b4e4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewController.swift @@ -80,7 +80,7 @@ class AlertViewController: ThemeActionSheetController { bind: { cell in cell.set(backgroundStyle: .transparent) }, - action: { [weak self] in + action: { [weak self] in self?.delegate?.onTapViewItem(index: index) } ) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewControllerNew.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewControllerNew.swift index 7122442299..b65a03e7f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewControllerNew.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Alert/AlertViewControllerNew.swift @@ -1,16 +1,16 @@ -import UIKit -import ThemeKit import SectionsTableView +import ThemeKit +import UIKit class AlertViewControllerNew: ThemeActionSheetController { private let alertTitle: String? private let viewItems: [ViewItem] private let reportAfterDismiss: Bool - private let onSelect: (Int) -> () + private let onSelect: (Int) -> Void private let tableView = SelfSizedSectionsTableView(style: .grouped) - private init(title: String?, viewItems: [ViewItem], reportAfterDismiss: Bool, onSelect: @escaping (Int) -> ()) { + private init(title: String?, viewItems: [ViewItem], reportAfterDismiss: Bool, onSelect: @escaping (Int) -> Void) { alertTitle = title self.viewItems = viewItems self.reportAfterDismiss = reportAfterDismiss @@ -19,7 +19,8 @@ class AlertViewControllerNew: ThemeActionSheetController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -42,27 +43,27 @@ class AlertViewControllerNew: ThemeActionSheetController { private func titleRow(text: String) -> RowProtocol { Row( - id: "title", - height: AlertTitleCell.height, - bind: { cell, _ in - cell.bind(text: text) - } + id: "title", + height: AlertTitleCell.height, + bind: { cell, _ in + cell.bind(text: text) + } ) } private func itemRow(viewItem: ViewItem, index: Int) -> RowProtocol { Row( - id: "item_\(index)", - hash: "\(viewItem.selected)", - height: .heightCell48, - bind: { cell, _ in - cell.set(backgroundStyle: .transparent) - cell.title = viewItem.text - cell.isSelected = viewItem.selected - cell.onSelect = { [weak self] in - self?.handleSelect(index: index) - } + id: "item_\(index)", + hash: "\(viewItem.selected)", + height: .heightCell48, + bind: { cell, _ in + cell.set(backgroundStyle: .transparent) + cell.title = viewItem.text + cell.isSelected = viewItem.selected + cell.onSelect = { [weak self] in + self?.handleSelect(index: index) } + } ) } @@ -76,11 +77,9 @@ class AlertViewControllerNew: ThemeActionSheetController { dismiss(animated: true) } } - } extension AlertViewControllerNew: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var rows = [RowProtocol]() @@ -92,11 +91,9 @@ extension AlertViewControllerNew: SectionsDataSource { return [Section(id: "main", rows: rows)] } - } extension AlertViewControllerNew { - struct ViewItem { let text: String let selected: Bool @@ -106,14 +103,11 @@ extension AlertViewControllerNew { self.selected = selected } } - } extension AlertViewControllerNew { - - static func instance(title: String? = nil, viewItems: [ViewItem], reportAfterDismiss: Bool = false, onSelect: @escaping (Int) -> ()) -> UIViewController { + static func instance(title: String? = nil, viewItems: [ViewItem], reportAfterDismiss: Bool = false, onSelect: @escaping (Int) -> Void) -> UIViewController { let controller = AlertViewControllerNew(title: title, viewItems: viewItems, reportAfterDismiss: reportAfterDismiss, onSelect: onSelect) return controller.toAlert } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/BackupModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/BackupModule.swift index ec13646662..ed73f733b3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/BackupModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/BackupModule.swift @@ -1,9 +1,8 @@ -import UIKit import ThemeKit +import UIKit struct BackupModule { - - static func manualViewController(account: Account, onComplete: (() -> ())? = nil) -> UIViewController? { + static func manualViewController(account: Account, onComplete: (() -> Void)? = nil) -> UIViewController? { guard let service = BackupService(account: account) else { return nil } @@ -21,7 +20,6 @@ struct BackupModule { return ThemeNavigationController(rootViewController: viewController) } - } extension BackupModule { @@ -53,4 +51,4 @@ extension BackupModule { let name: String let source: Source } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/AppBackupProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/AppBackupProvider.swift index 6370d099c1..5dc61765c9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/AppBackupProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/AppBackupProvider.swift @@ -138,16 +138,16 @@ extension AppBackupProvider { func restore(raws: [RawWalletBackup]) { let updated = raws.map { raw in let account = accountFactory.account( - type: raw.account.type, - origin: raw.account.origin, - backedUp: raw.account.backedUp, - fileBackedUp: raw.account.fileBackedUp, - name: raw.account.name + type: raw.account.type, + origin: raw.account.origin, + backedUp: raw.account.backedUp, + fileBackedUp: raw.account.fileBackedUp, + name: raw.account.name ) return RawWalletBackup(account: account, enabledWallets: raw.enabledWallets) } - accountManager.save(accounts: updated.map { $0.account }) + accountManager.save(accounts: updated.map(\.account)) updated.forEach { (raw: RawWalletBackup) in switch raw.account.type { @@ -155,7 +155,8 @@ extension AppBackupProvider { default: let wallets = raw.enabledWallets.compactMap { (wallet: WalletBackup.EnabledWallet) -> EnabledWallet? in guard let tokenQuery = TokenQuery(id: wallet.tokenQueryId), - BlockchainType.supported.contains(tokenQuery.blockchainType) else { + BlockchainType.supported.contains(tokenQuery.blockchainType) + else { return nil } @@ -170,11 +171,11 @@ extension AppBackupProvider { } return EnabledWallet( - tokenQueryId: wallet.tokenQueryId, - accountId: raw.account.id, - coinName: wallet.coinName, - coinCode: wallet.coinCode, - tokenDecimals: wallet.tokenDecimals + tokenQueryId: wallet.tokenQueryId, + accountId: raw.account.id, + coinName: wallet.coinName, + coinCode: wallet.coinCode, + tokenDecimals: wallet.tokenDecimals ) } walletManager.save(enabledWallets: wallets) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/BackupCloudModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/BackupCloudModule.swift index ac491d3782..c2563a310f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/BackupCloudModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/BackupCloudModule.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import HsToolKit +import ThemeKit +import UIKit class BackupCloudModule { static let minimumPassphraseLength = 8 @@ -28,11 +28,9 @@ class BackupCloudModule { return controller } - } extension BackupCloudModule { - enum PassphraseCharacterSet: CaseIterable { case lowerCased case upperCased @@ -52,5 +50,4 @@ extension BackupCloudModule { string.rangeOfCharacter(from: set) != nil } } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/FileStorage.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/FileStorage.swift index 42a74f48fc..27f5b2b07f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/FileStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/FileStorage.swift @@ -1,8 +1,8 @@ -import Foundation -import RxSwift -import RxRelay import Alamofire +import Foundation import HsToolKit +import RxRelay +import RxSwift class FileStorage { private let logger: Logger? @@ -44,8 +44,8 @@ class FileStorage { func deleteFile(url: URL?) throws { logger?.debug("=> FDStorage =>: Try to delete file") guard let url, - (try? FileManager.default.fileExists(coordinatingAccessAt: url).exists) ?? false else { - + (try? FileManager.default.fileExists(coordinatingAccessAt: url).exists) ?? false + else { logger?.debug("=> FDStorage =>: Can't find file! no need to remove") return } @@ -53,13 +53,10 @@ class FileStorage { try FileManager.default.removeItem(coordinatingAccessAt: url) logger?.debug("=> FDStorage =>: File deleted!") } - } extension FileStorage { - enum StorageError: Error { case cantCreateFile } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameService.swift index bb83f3cc2e..46e688c4af 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameService.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation import HsExtensions class ICloudBackupNameService { @@ -14,11 +14,9 @@ class ICloudBackupNameService { set(name: account.name) } - } extension ICloudBackupNameService { - var initialName: String { account.name } @@ -38,11 +36,9 @@ extension ICloudBackupNameService { state = .success(name: name) } - } extension ICloudBackupNameService { - enum State { case success(name: String) case failure(error: Error) @@ -52,5 +48,4 @@ extension ICloudBackupNameService { case empty case alreadyExist } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewController.swift index 4ed47892a2..ed51ba221a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewController.swift @@ -1,10 +1,10 @@ import Combine -import SnapKit -import ThemeKit -import UIKit import ComponentKit import SectionsTableView +import SnapKit +import ThemeKit import UIExtensions +import UIKit class ICloudBackupNameViewController: KeyboardAwareViewController { private let viewModel: ICloudBackupNameViewModel @@ -21,7 +21,7 @@ class ICloudBackupNameViewController: KeyboardAwareViewController { private var keyboardShown = false private var isLoaded = false - var onNext: ((String) -> ())? + var onNext: ((String) -> Void)? init(viewModel: ICloudBackupNameViewModel) { self.viewModel = viewModel @@ -29,7 +29,8 @@ class ICloudBackupNameViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: bottomView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -65,29 +66,27 @@ class ICloudBackupNameViewController: KeyboardAwareViewController { nameCautionCell.onChangeHeight = { [weak self] in self?.onChangeHeight() } - viewModel.$nameError - .receive(on: DispatchQueue.main) - .sink { [weak self] nameError in - guard let nameError else { - self?.nameCell.set(cautionType: nil) - self?.nameCautionCell.set(caution: nil) - return - } - - self?.nameCell.set(cautionType: .error) - self?.nameCautionCell.set(caution: Caution(text: nameError, type: .error)) + .receive(on: DispatchQueue.main) + .sink { [weak self] nameError in + guard let nameError else { + self?.nameCell.set(cautionType: nil) + self?.nameCautionCell.set(caution: nil) + return } - .store(in: &cancellables) - viewModel.$nextAvailable - .receive(on: DispatchQueue.main) - .sink { [weak self] available in - self?.navigationItem.rightBarButtonItem?.isEnabled = available - self?.nextButton.isEnabled = available - } - .store(in: &cancellables) + self?.nameCell.set(cautionType: .error) + self?.nameCautionCell.set(caution: Caution(text: nameError, type: .error)) + } + .store(in: &cancellables) + viewModel.$nextAvailable + .receive(on: DispatchQueue.main) + .sink { [weak self] available in + self?.navigationItem.rightBarButtonItem?.isEnabled = available + self?.nextButton.isEnabled = available + } + .store(in: &cancellables) tableView.buildSections() isLoaded = true @@ -114,52 +113,48 @@ class ICloudBackupNameViewController: KeyboardAwareViewController { let controller = BackupCloudModule.backupPassword(account: viewModel.account, name: name) navigationController?.pushViewController(controller, animated: true) } - } extension ICloudBackupNameViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "description-section", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.descriptionRow( - id: "description", - text: "backup.cloud.name.description".localized, - font: .subhead2, - textColor: .gray, - ignoreBottomMargin: true - ) - ] + id: "description-section", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.descriptionRow( + id: "description", + text: "backup.cloud.name.description".localized, + font: .subhead2, + textColor: .gray, + ignoreBottomMargin: true + ), + ] ), Section( - id: "name", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: nameCell, - id: "name", - height: .heightSingleLineCell - ), - StaticRow( - cell: nameCautionCell, - id: "name-caution", - dynamicHeight: { [weak self] width in - self?.nameCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + id: "name", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: nameCell, + id: "name", + height: .heightSingleLineCell + ), + StaticRow( + cell: nameCautionCell, + id: "name-caution", + dynamicHeight: { [weak self] width in + self?.nameCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), ] } - } extension ICloudBackupNameViewController: IDynamicHeightCellDelegate { - func onChangeHeight() { guard isLoaded else { return @@ -170,5 +165,4 @@ extension ICloudBackupNameViewController: IDynamicHeightCellDelegate { self?.tableView.endUpdates() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewModel.swift index daae77b268..8922ef4c28 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Name/ICloudBackupNameViewModel.swift @@ -13,15 +13,15 @@ class ICloudBackupNameViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } private func sync(state: ICloudBackupNameService.State) { switch state { - case .failure(let error): + case let .failure(error): nameError = error.localizedDescription nextAvailable = false case .success: @@ -29,11 +29,9 @@ class ICloudBackupNameViewModel { nextAvailable = true } } - } extension ICloudBackupNameViewModel { - var initialName: String { service.initialName } @@ -53,16 +51,13 @@ extension ICloudBackupNameViewModel { func onChange(name: String?) { service.set(name: name ?? "") } - } extension ICloudBackupNameService.NameError: LocalizedError { - var errorDescription: String? { switch self { case .empty: return "backup.cloud.name.error.empty".localized case .alreadyExist: return "backup.cloud.name.error.already_exist".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseService.swift index abf936caa0..f6dfda2b61 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseService.swift @@ -13,11 +13,9 @@ class BackupCloudPassphraseService { self.account = account self.name = name } - } extension BackupCloudPassphraseService { - func validate(text: String?) -> Bool { PassphraseValidator.validate(text: text) } @@ -38,15 +36,12 @@ extension BackupCloudPassphraseService { throw CreateError.cantSaveFile(error) } } - } extension BackupCloudPassphraseService { - enum CreateError: Error { case invalidConfirmation case urlNotAvailable case cantSaveFile(Error) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewController.swift index c92907aac1..e4d4ca3dbe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewController.swift @@ -1,10 +1,10 @@ import Combine -import SnapKit -import ThemeKit -import UIKit import ComponentKit import SectionsTableView +import SnapKit +import ThemeKit import UIExtensions +import UIKit class BackupCloudPassphraseViewController: KeyboardAwareViewController { private let viewModel: BackupCloudPassphraseViewModel @@ -32,7 +32,8 @@ class BackupCloudPassphraseViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -80,49 +81,49 @@ class BackupCloudPassphraseViewController: KeyboardAwareViewController { passphraseDescriptionCell.descriptionText = "restore.passphrase_description".localized viewModel.$passphraseCaution - .receive(on: DispatchQueue.main) - .sink { [weak self] caution in - self?.passphraseCell.set(cautionType: caution?.type) - self?.passphraseCautionCell.set(caution: caution) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] caution in + self?.passphraseCell.set(cautionType: caution?.type) + self?.passphraseCautionCell.set(caution: caution) + } + .store(in: &cancellables) viewModel.$passphraseConfirmationCaution - .receive(on: DispatchQueue.main) - .sink { [weak self] caution in - self?.passphraseConfirmationCell.set(cautionType: caution?.type) - self?.passphraseConfirmationCautionCell.set(caution: caution) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] caution in + self?.passphraseConfirmationCell.set(cautionType: caution?.type) + self?.passphraseConfirmationCautionCell.set(caution: caution) + } + .store(in: &cancellables) viewModel.$processing - .receive(on: DispatchQueue.main) - .sink { [weak self] processing in - self?.show(processing: processing) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] processing in + self?.show(processing: processing) + } + .store(in: &cancellables) viewModel.clearInputsPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.passphraseCell.inputText = nil - self?.passphraseConfirmationCell.inputText = nil - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.passphraseCell.inputText = nil + self?.passphraseConfirmationCell.inputText = nil + } + .store(in: &cancellables) viewModel.showErrorPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.show(error: $0) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.show(error: $0) + } + .store(in: &cancellables) viewModel.finishPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.finish() - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.finish() + } + .store(in: &cancellables) showDefaultPassphrase() @@ -178,83 +179,79 @@ class BackupCloudPassphraseViewController: KeyboardAwareViewController { dismiss(animated: true) } - } extension BackupCloudPassphraseViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "description-section", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.descriptionRow( - id: "description", - text: "backup.cloud.password.description".localized, - font: .subhead2, - textColor: .gray, - ignoreBottomMargin: true - ) - ] + id: "description-section", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.descriptionRow( + id: "description", + text: "backup.cloud.password.description".localized, + font: .subhead2, + textColor: .gray, + ignoreBottomMargin: true + ), + ] ), Section( - id: "passphrase", - footerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: passphraseCell, - id: "passphrase", - height: .heightSingleLineCell - ), - StaticRow( - cell: passphraseCautionCell, - id: "passphrase-caution", - dynamicHeight: { [weak self] width in - self?.passphraseCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "passphrase", + footerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: passphraseCell, + id: "passphrase", + height: .heightSingleLineCell + ), + StaticRow( + cell: passphraseCautionCell, + id: "passphrase-caution", + dynamicHeight: { [weak self] width in + self?.passphraseCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "confirm", - footerState: .margin(height: 20), - rows: [ - StaticRow( - cell: passphraseConfirmationCell, - id: "confirm", - height: .heightSingleLineCell - ), - StaticRow( - cell: passphraseConfirmationCautionCell, - id: "confirm-caution", - dynamicHeight: { [weak self] width in - self?.passphraseConfirmationCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "confirm", + footerState: .margin(height: 20), + rows: [ + StaticRow( + cell: passphraseConfirmationCell, + id: "confirm", + height: .heightSingleLineCell + ), + StaticRow( + cell: passphraseConfirmationCautionCell, + id: "confirm-caution", + dynamicHeight: { [weak self] width in + self?.passphraseConfirmationCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "highlighted-description", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: passphraseDescriptionCell, - id: "passphrase-description", - dynamicHeight: { [weak self] width in - self?.passphraseDescriptionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "highlighted-description", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: passphraseDescriptionCell, + id: "passphrase-description", + dynamicHeight: { [weak self] width in + self?.passphraseDescriptionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), ] } - } extension BackupCloudPassphraseViewController: IDynamicHeightCellDelegate { - func onChangeHeight() { guard isLoaded else { return @@ -265,5 +262,4 @@ extension BackupCloudPassphraseViewController: IDynamicHeightCellDelegate { self?.tableView.endUpdates() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewModel.swift index 076f1b8988..f90c70af5f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Passphrase/BackupCloudPassphraseViewModel.swift @@ -27,11 +27,9 @@ class BackupCloudPassphraseViewModel { passphraseConfirmationCaution = nil } } - } extension BackupCloudPassphraseViewModel { - var clearInputsPublisher: AnyPublisher { clearInputsSubject.eraseToAnyPublisher() } @@ -44,7 +42,6 @@ extension BackupCloudPassphraseViewModel { finishSubject.eraseToAnyPublisher() } - func onChange(passphrase: String) { service.passphrase = passphrase clearCautions() @@ -94,7 +91,6 @@ extension BackupCloudPassphraseViewModel { processing = false } } - } extension BackupCrypto.ValidationError: LocalizedError { @@ -124,4 +120,3 @@ extension CloudBackupManager.BackupError: LocalizedError { } } } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsService.swift index 5f4cd25e40..e35ac6480c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsService.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation import HsExtensions class ICloudBackupTermsService { @@ -14,18 +14,17 @@ class ICloudBackupTermsService { self.account = account self.cloudAccountBackupManager = cloudAccountBackupManager } - } extension ICloudBackupTermsService { - var cloudIsAvailable: Bool { cloudAccountBackupManager.isAvailable } func toggleTerm(at index: Int) { - guard case .selectedTerms(var checkedIndices) = state, - index < termCount else { + guard case var .selectedTerms(checkedIndices) = state, + index < termCount + else { return } @@ -37,14 +36,11 @@ extension ICloudBackupTermsService { state = .selectedTerms(checkedIndices) } - } extension ICloudBackupTermsService { - enum State { case iCloudNotAvailable case selectedTerms(Set) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewController.swift index 36c18b0d67..82c79d06ad 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import SnapKit import Combine -import ThemeKit import ComponentKit -import UIExtensions import SectionsTableView +import SnapKit +import ThemeKit +import UIExtensions +import UIKit class ICloudBackupTermsViewController: ThemeViewController { private let viewModel: ICloudBackupTermsViewModel @@ -22,7 +22,8 @@ class ICloudBackupTermsViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -55,35 +56,34 @@ class ICloudBackupTermsViewController: ThemeViewController { viewItems = viewModel.viewItems viewModel.$viewItems - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.viewItems = $0 - self?.reloadTable() - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.viewItems = $0 + self?.reloadTable() + } + .store(in: &cancellables) continueButton.isEnabled = viewModel.buttonEnabled viewModel.$buttonEnabled - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.continueButton.isEnabled = $0 - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.continueButton.isEnabled = $0 + } + .store(in: &cancellables) viewModel.showModulePublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.showModule() - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.showModule() + } + .store(in: &cancellables) viewModel.showCloudNotAvailablePublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.showNotCloudAvailable() - } - .store(in: &cancellables) - + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.showNotCloudAvailable() + } + .store(in: &cancellables) loaded = true reloadTable() @@ -112,48 +112,46 @@ class ICloudBackupTermsViewController: ThemeViewController { tableView.reload(animated: true) } } - } extension ICloudBackupTermsViewController: SectionsDataSource { - private func row(viewItem: ICloudBackupTermsViewModel.ViewItem, index: Int, isFirst: Bool, isLast: Bool) -> RowProtocol { let backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence let textFont: UIFont = .subhead2 let text = viewItem.text return CellBuilderNew.row( - rootElement: .hStack([ - .image24 { component in - component.imageView.image = UIImage(named: viewItem.checked ? "checkbox_active_24" : "checkbox_diactive_24") - }, - .text { component in - component.font = textFont - component.textColor = .themeLeah - component.text = text - component.numberOfLines = 0 - } - ]), - tableView: tableView, - id: "row-\(index)", - hash: "\(viewItem.checked)", - autoDeselect: true, - dynamicHeight: { width in - CellBuilderNew.height( - containerWidth: width, - backgroundStyle: backgroundStyle, - text: text, - font: textFont, - verticalPadding: .margin16, - elements: [.fixed(width: .iconSize24), .multiline] - ) + rootElement: .hStack([ + .image24 { component in + component.imageView.image = UIImage(named: viewItem.checked ? "checkbox_active_24" : "checkbox_diactive_24") }, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + .text { component in + component.font = textFont + component.textColor = .themeLeah + component.text = text + component.numberOfLines = 0 }, - action: { [weak self] in - self?.viewModel.onToggle(index: index) - } + ]), + tableView: tableView, + id: "row-\(index)", + hash: "\(viewItem.checked)", + autoDeselect: true, + dynamicHeight: { width in + CellBuilderNew.height( + containerWidth: width, + backgroundStyle: backgroundStyle, + text: text, + font: textFont, + verticalPadding: .margin16, + elements: [.fixed(width: .iconSize24), .multiline] + ) + }, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + }, + action: { [weak self] in + self?.viewModel.onToggle(index: index) + } ) } @@ -165,10 +163,10 @@ extension ICloudBackupTermsViewController: SectionsDataSource { footerState: .margin(height: .margin32), rows: [ tableView.highlightedDescriptionRow( - id: "description", - text: "backup.cloud.description".localized, - ignoreBottomMargin: true - ) + id: "description", + text: "backup.cloud.description".localized, + ignoreBottomMargin: true + ), ] ), Section( @@ -177,8 +175,7 @@ extension ICloudBackupTermsViewController: SectionsDataSource { rows: viewItems.enumerated().map { index, viewItem in row(viewItem: viewItem, index: index, isFirst: index == 0, isLast: index == viewItems.count - 1) } - ) + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewModel.swift index 42033e719e..15d842334e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/ICloud/Terms/ICloudBackupTermsViewModel.swift @@ -15,8 +15,8 @@ class ICloudBackupTermsViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } @@ -26,17 +26,15 @@ class ICloudBackupTermsViewModel { return } - viewItems = (0.. Bool { + static func == (lhs: ViewItem, rhs: ViewItem) -> Bool { lhs.text == rhs.text && - lhs.checked == rhs.checked + lhs.checked == rhs.checked } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupService.swift index b403834e32..a891d2a647 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupService.swift @@ -12,5 +12,4 @@ class BackupService { self.words = words self.salt = salt } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewController.swift index 3794987c36..62b19a34ce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewController.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView import ComponentKit +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class BackupViewController: ThemeViewController { private let viewModel: BackupViewModel - var onComplete: (() -> ())? + var onComplete: (() -> Void)? private let tableView = SectionsTableView(style: .grouped) @@ -18,7 +18,8 @@ class BackupViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -83,11 +84,9 @@ class BackupViewController: ThemeViewController { visible = !visible tableView.reload() } - } extension BackupViewController: SectionsDataSource { - private func marginRow(id: String, height: CGFloat) -> RowProtocol { Row(id: id, height: height) } @@ -98,46 +97,46 @@ extension BackupViewController: SectionsDataSource { var rows: [RowProtocol] = [ Row( - id: "mnemonic", - dynamicHeight: { width in - MnemonicPhraseCell.height(containerWidth: width, words: words) - }, - bind: { cell, _ in - cell.set(state: state) - }, - action: { [weak self] _ in - self?.toggle() - } - ) + id: "mnemonic", + dynamicHeight: { width in + MnemonicPhraseCell.height(containerWidth: width, words: words) + }, + bind: { cell, _ in + cell.set(state: state) + }, + action: { [weak self] _ in + self?.toggle() + } + ), ] let visible = visible if let passphrase = viewModel.passphrase { let passphraseRow = CellBuilderNew.row( - rootElement: .hStack([ - .image24 { component in - component.imageView.image = UIImage(named: "key_phrase_24")?.withTintColor(.themeGray) - }, - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = "backup.passphrase".localized - }, - .secondaryButton { component in - component.button.set(style: .default) - component.button.setTitle(visible ? passphrase : BalanceHiddenManager.placeholder, for: .normal) - component.onTap = { - CopyHelper.copyAndNotify(value: passphrase) - } + rootElement: .hStack([ + .image24 { component in + component.imageView.image = UIImage(named: "key_phrase_24")?.withTintColor(.themeGray) + }, + .text { component in + component.font = .subhead2 + component.textColor = .themeGray + component.text = "backup.passphrase".localized + }, + .secondaryButton { component in + component.button.set(style: .default) + component.button.setTitle(visible ? passphrase : BalanceHiddenManager.placeholder, for: .normal) + component.onTap = { + CopyHelper.copyAndNotify(value: passphrase) } - ]), - tableView: tableView, - id: "passphrase", - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - } + }, + ]), + tableView: tableView, + id: "passphrase", + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + } ) rows.append(marginRow(id: "passphrase-margin", height: .margin24)) @@ -146,15 +145,14 @@ extension BackupViewController: SectionsDataSource { return [ Section( - id: "description", - footerState: tableView.sectionFooter(text: "backup.description".localized) + id: "description", + footerState: tableView.sectionFooter(text: "backup.description".localized) ), Section( - id: "main", - footerState: .margin(height: .margin32), - rows: rows - ) + id: "main", + footerState: .margin(height: .margin32), + rows: rows + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewModel.swift index dcbca6ac07..cd78d20f91 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Backup/Manual/BackupViewModel.swift @@ -4,11 +4,9 @@ class BackupViewModel { init(service: BackupService) { self.service = service } - } extension BackupViewModel { - var account: Account { service.account } @@ -20,5 +18,4 @@ extension BackupViewModel { var passphrase: String? { service.salt.isEmpty ? nil : service.salt } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordCell.swift index 7e217cce5e..60db5641f5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordCell.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class BackupMnemonicWordCell: UICollectionViewCell { private let button = SecondaryButton() - private var onTap: (() -> ())? + private var onTap: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) @@ -20,7 +20,8 @@ class BackupMnemonicWordCell: UICollectionViewCell { button.addTarget(self, action: #selector(onTapButton), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -28,19 +29,16 @@ class BackupMnemonicWordCell: UICollectionViewCell { onTap?() } - func bind(viewItem: BackupVerifyWordsViewModel.WordViewItem, onTap: @escaping () -> ()) { + func bind(viewItem: BackupVerifyWordsViewModel.WordViewItem, onTap: @escaping () -> Void) { button.setTitle(viewItem.text, for: .normal) button.isEnabled = viewItem.enabled self.onTap = onTap } - } extension BackupMnemonicWordCell { - static func size(word: String) -> CGSize { CGSize(width: SecondaryButton.width(title: word, style: .default, hasImage: false), height: SecondaryButton.height(style: .default)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordsCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordsCell.swift index c675d1ce9d..ff9b817d9e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordsCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupMnemonicWordsCell.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import ComponentKit import CollectionViewCenteredFlowLayout +import ComponentKit +import SnapKit +import ThemeKit +import UIKit class BackupMnemonicWordsCell: UITableViewCell { private static let horizontalPadding: CGFloat = .margin16 @@ -10,7 +10,7 @@ class BackupMnemonicWordsCell: UITableViewCell { private static let lineSpacing: CGFloat = .margin16 private var viewItems = [BackupVerifyWordsViewModel.WordViewItem]() - private var onTap: ((Int) -> ())? + private var onTap: ((Int) -> Void)? private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: CollectionViewCenteredFlowLayout()) @@ -33,39 +33,34 @@ class BackupMnemonicWordsCell: UITableViewCell { collectionView.register(BackupMnemonicWordCell.self, forCellWithReuseIdentifier: String(describing: BackupMnemonicWordCell.self)) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension BackupMnemonicWordsCell { - - func set(viewItems: [BackupVerifyWordsViewModel.WordViewItem], onTap: @escaping (Int) -> ()) { + func set(viewItems: [BackupVerifyWordsViewModel.WordViewItem], onTap: @escaping (Int) -> Void) { self.viewItems = viewItems self.onTap = onTap collectionView.reloadData() collectionView.layoutIfNeeded() } - } extension BackupMnemonicWordsCell: UICollectionViewDataSource { - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + public func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { viewItems.count } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: BackupMnemonicWordCell.self), for: indexPath) } - } extension BackupMnemonicWordsCell: UICollectionViewDelegate { - - public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + public func collectionView(_: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? BackupMnemonicWordCell { let index = indexPath.item @@ -74,27 +69,23 @@ extension BackupMnemonicWordsCell: UICollectionViewDelegate { } } } - } extension BackupMnemonicWordsCell: UICollectionViewDelegateFlowLayout { - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { BackupMnemonicWordCell.size(word: viewItems[indexPath.item].text) } - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { Self.itemSpacing } - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumLineSpacingForSectionAt _: Int) -> CGFloat { Self.lineSpacing } - } extension BackupMnemonicWordsCell { - static func height(containerWidth: CGFloat, viewItems: [BackupVerifyWordsViewModel.WordViewItem]) -> CGFloat { let collectionWidth = containerWidth - horizontalPadding * 2 @@ -118,5 +109,4 @@ extension BackupMnemonicWordsCell { let collectionHeight = CGFloat(lines) * lineHeight + CGFloat(lines - 1) * lineSpacing return collectionHeight } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsModule.swift index f0c1b44885..89145e538d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsModule.swift @@ -1,8 +1,7 @@ import UIKit struct BackupVerifyWordsModule { - - static func viewController(account: Account, onComplete: (() -> ())? = nil) -> UIViewController? { + static func viewController(account: Account, onComplete: (() -> Void)? = nil) -> UIViewController? { guard let service = BackupVerifyWordsService(account: account, accountManager: App.shared.accountManager, appManager: App.shared.appManager) else { return nil } @@ -12,5 +11,4 @@ struct BackupVerifyWordsModule { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsService.swift index 52abb55d30..d3e7ae73d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsService.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift class BackupVerifyWordsService { let account: Account @@ -10,7 +10,7 @@ class BackupVerifyWordsService { private let disposeBag = DisposeBag() private let stateRelay = PublishRelay() - private(set) var state: State = State(inputItems: [], wordItems: []) { + private(set) var state: State = .init(inputItems: [], wordItems: []) { didSet { stateRelay.accept(state) } @@ -41,26 +41,24 @@ class BackupVerifyWordsService { let validatedWords = inputWords.prefix(validatedWordCount) state = State( - inputItems: inputWords.enumerated().map { index, word in - InputItem( - index: word.index, - text: validatedWords.contains(word) ? word.text : nil, - current: index == validatedWordCount - ) - }, - wordItems: suggestionWords.map { word in - WordItem( - text: word.text, - enabled: !validatedWords.contains(word) - ) - } + inputItems: inputWords.enumerated().map { index, word in + InputItem( + index: word.index, + text: validatedWords.contains(word) ? word.text : nil, + current: index == validatedWordCount + ) + }, + wordItems: suggestionWords.map { word in + WordItem( + text: word.text, + enabled: !validatedWords.contains(word) + ) + } ) } - } extension BackupVerifyWordsService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -82,10 +80,10 @@ extension BackupVerifyWordsService { // if hasSalt { // return .showPassphrase // } else { - account.backedUp = true - accountManager.update(account: account) + account.backedUp = true + accountManager.update(account: account) - return .backedUp + return .backedUp // } } else { return .correct @@ -100,11 +98,9 @@ extension BackupVerifyWordsService { syncState() } - } extension BackupVerifyWordsService { - enum ActionResult { case correct case incorrect @@ -132,9 +128,8 @@ extension BackupVerifyWordsService { let index: Int let text: String - static func ==(lhs: Word, rhs: Word) -> Bool { + static func == (lhs: Word, rhs: Word) -> Bool { lhs.index == rhs.index } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewController.swift index 3d27cecae1..eed452c0a6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import RxSwift +import ComponentKit import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import SnapKit +import ThemeKit +import UIKit class BackupVerifyWordsViewController: ThemeViewController { private let viewModel: BackupVerifyWordsViewModel @@ -16,7 +16,7 @@ class BackupVerifyWordsViewController: ThemeViewController { private var isLoaded = false private var didAppear = false - var onComplete: (() -> ())? + var onComplete: (() -> Void)? init(viewModel: BackupVerifyWordsViewModel) { self.viewModel = viewModel @@ -24,7 +24,8 @@ class BackupVerifyWordsViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -90,14 +91,12 @@ class BackupVerifyWordsViewController: ThemeViewController { tableView.reload() } - private func openPassphrase(account: Account) { + private func openPassphrase(account _: Account) { // may be implemented later } - } extension BackupVerifyWordsViewController: SectionsDataSource { - private func marginRow(id: String, height: CGFloat) -> RowProtocol { Row(id: id, height: height) } @@ -107,18 +106,18 @@ extension BackupVerifyWordsViewController: SectionsDataSource { for (index, viewItem) in viewItem.inputViewItems.enumerated() { let row = CellBuilderNew.row( - rootElement: .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = viewItem.text - }, - tableView: tableView, - id: "input-\(index)", - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .bordered, isFirst: true, isLast: true) - cell.wrapperView.borderColor = viewItem.selected ? .themeYellow50 : .themeSteel20 - } + rootElement: .text { component in + component.font = .body + component.textColor = .themeLeah + component.text = viewItem.text + }, + tableView: tableView, + id: "input-\(index)", + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .bordered, isFirst: true, isLast: true) + cell.wrapperView.borderColor = viewItem.selected ? .themeYellow50 : .themeSteel20 + } ) rows.append(row) @@ -129,32 +128,31 @@ extension BackupVerifyWordsViewController: SectionsDataSource { return [ Section( - id: "description", - footerState: tableView.sectionFooter(text: "backup_verify_words.description".localized) + id: "description", + footerState: tableView.sectionFooter(text: "backup_verify_words.description".localized) ), Section( - id: "main", - footerState: .margin(height: .margin16), - rows: rows + id: "main", + footerState: .margin(height: .margin16), + rows: rows ), Section( - id: "suggestions", - footerState: .margin(height: .margin32), - rows: [ - Row( - id: "suggestions", - dynamicHeight: { width in - BackupMnemonicWordsCell.height(containerWidth: width, viewItems: wordViewItems) - }, - bind: { cell, _ in - cell.set(viewItems: wordViewItems) { [weak self] index in - self?.viewModel.onSelectWord(index: index) - } - } - ) - ] - ) + id: "suggestions", + footerState: .margin(height: .margin32), + rows: [ + Row( + id: "suggestions", + dynamicHeight: { width in + BackupMnemonicWordsCell.height(containerWidth: width, viewItems: wordViewItems) + }, + bind: { cell, _ in + cell.set(viewItems: wordViewItems) { [weak self] index in + self?.viewModel.onSelectWord(index: index) + } + } + ), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewModel.swift index cab69cf742..7704fd96ca 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BackupVerifyWords/BackupVerifyWordsViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class BackupVerifyWordsViewModel { private let service: BackupVerifyWordsService @@ -9,7 +9,7 @@ class BackupVerifyWordsViewModel { private let viewItemRelay = BehaviorRelay(value: ViewItem(inputViewItems: [], wordViewItems: [])) private let errorRelay = PublishRelay() private let openPassphraseRelay = PublishRelay() - private let successRelay = PublishRelay<()>() + private let successRelay = PublishRelay() init(service: BackupVerifyWordsService) { self.service = service @@ -21,27 +21,25 @@ class BackupVerifyWordsViewModel { private func sync(state: BackupVerifyWordsService.State) { let viewItem = ViewItem( - inputViewItems: state.inputItems.map { item in - InputViewItem( - text: "\(item.index)." + (item.text.map { " \($0)" } ?? ""), - selected: item.current - ) - }, - wordViewItems: state.wordItems.map { item in - WordViewItem( - text: item.text, - enabled: item.enabled - ) - } + inputViewItems: state.inputItems.map { item in + InputViewItem( + text: "\(item.index)." + (item.text.map { " \($0)" } ?? ""), + selected: item.current + ) + }, + wordViewItems: state.wordItems.map { item in + WordViewItem( + text: item.text, + enabled: item.enabled + ) + } ) viewItemRelay.accept(viewItem) } - } extension BackupVerifyWordsViewModel { - var viewItemDriver: Driver { viewItemRelay.asDriver() } @@ -54,7 +52,7 @@ extension BackupVerifyWordsViewModel { openPassphraseRelay.asSignal() } - var successSignal: Signal<()> { + var successSignal: Signal { successRelay.asSignal() } @@ -72,11 +70,9 @@ extension BackupVerifyWordsViewModel { case .backedUp: successRelay.accept(()) } } - } extension BackupVerifyWordsViewModel { - struct ViewItem { let inputViewItems: [InputViewItem] let wordViewItems: [WordViewItem] @@ -91,5 +87,4 @@ extension BackupVerifyWordsViewModel { let text: String let enabled: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorModule.swift index 44f01f4f7d..a5e0218fc1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorModule.swift @@ -1,19 +1,17 @@ import UIKit struct BalanceErrorModule { - static func viewController(wallet: Wallet, error: Error, sourceViewController: UIViewController?) -> UIViewController { let service = BalanceErrorService( - wallet: wallet, - error: error, - adapterManager: App.shared.adapterManager, - btcBlockchainManager: App.shared.btcBlockchainManager, - evmBlockchainManager: App.shared.evmBlockchainManager + wallet: wallet, + error: error, + adapterManager: App.shared.adapterManager, + btcBlockchainManager: App.shared.btcBlockchainManager, + evmBlockchainManager: App.shared.evmBlockchainManager ) let viewModel = BalanceErrorViewModel(service: service) let viewController = BalanceErrorViewController(viewModel: viewModel, sourceViewController: sourceViewController) return viewController.toBottomSheet } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorService.swift index f60227f4aa..1ed2da2e37 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorService.swift @@ -18,11 +18,9 @@ class BalanceErrorService { item = .evm(blockchain: blockchain) } } - } extension BalanceErrorService { - var coinName: String { wallet.coin.name } @@ -38,14 +36,11 @@ extension BalanceErrorService { func refreshWallet() { adapterManager.refresh(wallet: wallet) } - } extension BalanceErrorService { - enum Item { case btc(blockchain: Blockchain) case evm(blockchain: Blockchain) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewController.swift index e86c0dc1a7..aacbb638b2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import MessageUI import ComponentKit -import RxSwift import MarketKit +import MessageUI +import RxSwift +import SnapKit +import ThemeKit +import UIKit class BalanceErrorViewController: ThemeActionSheetController { private let viewModel: BalanceErrorViewModel @@ -21,7 +21,8 @@ class BalanceErrorViewController: ThemeActionSheetController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -34,9 +35,9 @@ class BalanceErrorViewController: ThemeActionSheetController { } titleView.bind( - image: .warning, - title: "balance_error.sync_error".localized, - viewController: self + image: .warning, + title: "balance_error.sync_error".localized, + viewController: self ) let retryButton = PrimaryButton() @@ -121,13 +122,10 @@ class BalanceErrorViewController: ThemeActionSheetController { self?.sourceViewController?.present(EvmNetworkModule.viewController(blockchain: blockchain), animated: true) } } - } extension BalanceErrorViewController: MFMailComposeViewControllerDelegate { - - func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error _: Error?) { controller.dismiss(animated: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewModel.swift index 6c78c7b6aa..0f78297e82 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BalanceError/BalanceErrorViewModel.swift @@ -1,24 +1,22 @@ -import UIKit -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift +import UIKit class BalanceErrorViewModel { private let service: BalanceErrorService private let openBtcBlockchainRelay = PublishRelay() private let openEvmBlockchainRelay = PublishRelay() - private let finishRelay = PublishRelay<()>() + private let finishRelay = PublishRelay() init(service: BalanceErrorService) { self.service = service } - } extension BalanceErrorViewModel { - var openBtcBlockchainSignal: Signal { openBtcBlockchainRelay.asSignal() } @@ -27,7 +25,7 @@ extension BalanceErrorViewModel { openEvmBlockchainRelay.asSignal() } - var finishSignal: Signal<()> { + var finishSignal: Signal { finishRelay.asSignal() } @@ -55,11 +53,10 @@ extension BalanceErrorViewModel { } switch item { - case .btc(let blockchain): + case let .btc(blockchain): openBtcBlockchainRelay.accept(blockchain) - case .evm(let blockchain): + case let .evm(blockchain): openEvmBlockchainRelay.accept(blockchain) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceCexProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceCexProvider.swift index 04251cc3cb..4f52a5b9d3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceCexProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceCexProvider.swift @@ -1,9 +1,9 @@ -import Foundation -import Crypto import Alamofire -import ObjectMapper -import MarketKit +import Crypto +import Foundation import HsToolKit +import MarketKit +import ObjectMapper class BinanceCexProvider { private static let baseUrl = "https://api.binance.com" @@ -473,11 +473,9 @@ class BinanceCexProvider { private func fetch(path: String, method: HTTPMethod = .get, parameters: Parameters = [:]) async throws -> [T] { try await Self.fetch(networkManager: networkManager, apiKey: apiKey, secret: secret, path: path, method: method, parameters: parameters) } - } extension BinanceCexProvider: ICexAssetProvider { - func assets() async throws -> [CexAssetResponse] { let response: [AssetResponse] = try await fetch(path: "/sapi/v1/capital/config/getall") @@ -485,53 +483,51 @@ extension BinanceCexProvider: ICexAssetProvider { let blockchainUidMap = try await blockchainUidMap() return response - .filter { asset in - !asset.isLegalMoney - } - .map { asset in - CexAssetResponse( - id: asset.coin, - name: asset.name, - freeBalance: asset.free, - lockedBalance: asset.locked, - depositEnabled: asset.depositAllEnable, - withdrawEnabled: false, - depositNetworks: asset.networks.map { network in - CexDepositNetworkRaw( - id: network.network, - name: network.name, - isDefault: network.isDefault, - enabled: network.depositEnable, - minAmount: 0, - blockchainUid: blockchainUidMap[network.network] - ) - }, - withdrawNetworks: asset.networks.map { network in - CexWithdrawNetworkRaw( - id: network.network, - name: network.name, - isDefault: network.isDefault, - enabled: network.withdrawEnable, - minAmount: network.withdrawMin, - maxAmount: network.withdrawMax, - fixedFee: network.withdrawFee, - feePercent: 0, - minFee: 0, - blockchainUid: blockchainUidMap[network.network] - ) - }, - coinUid: coinUidMap[asset.coin] - ) - } + .filter { asset in + !asset.isLegalMoney + } + .map { asset in + CexAssetResponse( + id: asset.coin, + name: asset.name, + freeBalance: asset.free, + lockedBalance: asset.locked, + depositEnabled: asset.depositAllEnable, + withdrawEnabled: false, + depositNetworks: asset.networks.map { network in + CexDepositNetworkRaw( + id: network.network, + name: network.name, + isDefault: network.isDefault, + enabled: network.depositEnable, + minAmount: 0, + blockchainUid: blockchainUidMap[network.network] + ) + }, + withdrawNetworks: asset.networks.map { network in + CexWithdrawNetworkRaw( + id: network.network, + name: network.name, + isDefault: network.isDefault, + enabled: network.withdrawEnable, + minAmount: network.withdrawMin, + maxAmount: network.withdrawMax, + fixedFee: network.withdrawFee, + feePercent: 0, + minFee: 0, + blockchainUid: blockchainUidMap[network.network] + ) + }, + coinUid: coinUidMap[asset.coin] + ) + } } - } extension BinanceCexProvider: ICexDepositProvider { - func deposit(id: String, network: String?) async throws -> (String, String?) { var parameters: Parameters = [ - "coin": id + "coin": id, ] if let network { @@ -541,16 +537,14 @@ extension BinanceCexProvider: ICexDepositProvider { let response: DepositResponse = try await fetch(path: "/sapi/v1/capital/deposit/address", parameters: parameters) return (response.address, response.tag.isEmpty ? nil : response.tag) } - } extension BinanceCexProvider { - - func withdraw(id: String, network: String?, address: String, amount: Decimal, feeFromAmount: Bool?) async throws -> String { + func withdraw(id: String, network: String?, address: String, amount: Decimal, feeFromAmount _: Bool?) async throws -> String { var parameters: Parameters = [ "coin": id, "address": address, - "amount": amount + "amount": amount, ] if let network { @@ -560,19 +554,15 @@ extension BinanceCexProvider { let response: WithdrawResponse = try await fetch(path: "/sapi/v1/capital/withdraw/apply", method: .post, parameters: parameters) return response.id } - } extension BinanceCexProvider { - static func validate(apiKey: String, secret: String, networkManager: NetworkManager) async throws { let _: [AssetResponse] = try await Self.fetch(networkManager: networkManager, apiKey: apiKey, secret: secret, path: "/sapi/v1/capital/config/getall") } - } extension BinanceCexProvider { - private struct AssetResponse: ImmutableMappable { let coin: String let name: String @@ -639,5 +629,4 @@ extension BinanceCexProvider { case invalidSecret case invalidQueryString } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceWithdrawHandler.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceWithdrawHandler.swift index ba0ac7f4bf..8737b763fd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceWithdrawHandler.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/BinanceWithdrawHandler.swift @@ -12,8 +12,7 @@ class BinanceWithdrawHandler: ICexWithdrawHandler { try await provider.withdraw(id: id, network: network, address: address, amount: amount, feeFromAmount: feeFromAmount) } - func handle(result: Any, viewController: UIViewController) { + func handle(result _: Any, viewController _: UIViewController) { // todo } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceModule.swift index a4e044d198..89ebbfa812 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceModule.swift @@ -1,16 +1,14 @@ import UIKit struct RestoreBinanceModule { - static func viewController(returnViewController: UIViewController?) -> UIViewController { let service = RestoreBinanceService( - networkManager: App.shared.networkManager, - accountFactory: App.shared.accountFactory, - accountManager: App.shared.accountManager + networkManager: App.shared.networkManager, + accountFactory: App.shared.accountFactory, + accountManager: App.shared.accountManager ) let viewModel = RestoreBinanceViewModel(service: service) return RestoreBinanceViewController(viewModel: viewModel, returnViewController: returnViewController) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceService.swift index b423f55181..5ee772de63 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceService.swift @@ -1,7 +1,7 @@ import Combine -import ObjectMapper -import HsToolKit import HsExtensions +import HsToolKit +import ObjectMapper class RestoreBinanceService { private let networkManager: NetworkManager @@ -42,11 +42,9 @@ class RestoreBinanceService { state = .connected } - } extension RestoreBinanceService { - func parse(qrCodeString: String) throws -> QrCode { try QrCode(JSONString: qrCodeString) } @@ -63,11 +61,9 @@ extension RestoreBinanceService { } }.store(in: &tasks) } - } extension RestoreBinanceService { - enum State { case notReady case idle(error: Error?) @@ -84,5 +80,4 @@ extension RestoreBinanceService { secretKey = try map.value("secretKey") } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceViewModel.swift index ed14db9293..d1e431ad28 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Binance/RestoreBinance/RestoreBinanceViewModel.swift @@ -16,8 +16,8 @@ class RestoreBinanceViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } @@ -28,7 +28,7 @@ class RestoreBinanceViewModel { connectEnabled = false connectVisible = true connectingVisible = false - case .idle(let error): + case let .idle(error): connectEnabled = true connectVisible = true connectingVisible = false @@ -43,11 +43,9 @@ class RestoreBinanceViewModel { successSubject.send() } } - } extension RestoreBinanceViewModel { - var valuesPublisher: AnyPublisher<(String, String), Never> { valuesSubject.eraseToAnyPublisher() } @@ -83,5 +81,4 @@ extension RestoreBinanceViewModel { func onTapConnect() { service.connect() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BirthdayInput/BirthdayInputViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BirthdayInput/BirthdayInputViewController.swift index cee4338342..4bd47d66e0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BirthdayInput/BirthdayInputViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BirthdayInput/BirthdayInputViewController.swift @@ -1,16 +1,16 @@ -import UIKit -import ThemeKit import ComponentKit -import UIExtensions -import SnapKit import MarketKit import SectionsTableView +import SnapKit +import ThemeKit +import UIExtensions +import UIKit class BirthdayInputViewController: KeyboardAwareViewController { private let token: Token - var onEnterBirthdayHeight: ((Int?) -> ())? - var onCancel: (() -> ())? + var onEnterBirthdayHeight: ((Int?) -> Void)? + var onCancel: (() -> Void)? private let iconImageView = UIImageView() private let tableView = SectionsTableView(style: .grouped) @@ -31,7 +31,8 @@ class BirthdayInputViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -100,15 +101,15 @@ class BirthdayInputViewController: KeyboardAwareViewController { // show disclaimer let viewController = BottomSheetModule.viewController( - image: .warning, - title: "alert.warning".localized, - items: [ - .highlightedDescription(text: "restore_setting.download.disclaimer".localized) - ], - buttons: [ - .init(style: .yellow, title: "button.continue".localized, actionType: .afterClose) { [ weak self] in self?.setOldTypeActive(showKeyboard: showKeyboard) }, - .init(style: .transparent, title: "button.cancel".localized) - ] + image: .warning, + title: "alert.warning".localized, + items: [ + .highlightedDescription(text: "restore_setting.download.disclaimer".localized), + ], + buttons: [ + .init(style: .yellow, title: "button.continue".localized, actionType: .afterClose) { [weak self] in self?.setOldTypeActive(showKeyboard: showKeyboard) }, + .init(style: .transparent, title: "button.cancel".localized), + ] ) present(viewController, animated: true) @@ -143,17 +144,17 @@ class BirthdayInputViewController: KeyboardAwareViewController { private func row(type: WalletType) -> RowProtocol { tableView.universalRow62( - id: "wallet_type_\(type.title)", - title: .body(type.title), - description: .subhead2(type.description), - accessoryType: .check(type == walletType), - hash: "wallet_type_\(type.title)_\(type == walletType)", - autoDeselect: true, - isFirst: type.rawValue == 0, - isLast: type.rawValue == WalletType.allCases.count - 1, - action: { [weak self] in - self?.didTap(type: type) - } + id: "wallet_type_\(type.title)", + title: .body(type.title), + description: .subhead2(type.description), + accessoryType: .check(type == walletType), + hash: "wallet_type_\(type.title)_\(type == walletType)", + autoDeselect: true, + isFirst: type.rawValue == 0, + isLast: type.rawValue == WalletType.allCases.count - 1, + action: { [weak self] in + self?.didTap(type: type) + } ) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensModule.swift index d6c260694b..a91d709301 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensModule.swift @@ -1,5 +1,4 @@ -struct BlockchainTokensModule { - +enum BlockchainTokensModule { static func module() -> (BlockchainTokensService, BlockchainTokensView) { let service = BlockchainTokensService() let viewModel = BlockchainTokensViewModel(service: service) @@ -7,5 +6,4 @@ struct BlockchainTokensModule { return (service, view) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensService.swift index 4e006b0672..4760593242 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensService.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class BlockchainTokensService { private let approveTokensRelay = PublishRelay<(Blockchain, [Token])>() @@ -12,7 +12,6 @@ class BlockchainTokensService { } extension BlockchainTokensService { - var approveTokensObservable: Observable<(Blockchain, [Token])> { approveTokensRelay.asObservable() } @@ -47,16 +46,13 @@ extension BlockchainTokensService { rejectApproveTokensRelay.accept(request.blockchain) } - } extension BlockchainTokensService { - struct Request { let blockchain: Blockchain let tokens: [Token] let enabledTokens: [Token] let allowEmpty: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensView.swift index 2398377f81..e5fa53d44d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensView.swift @@ -1,12 +1,12 @@ -import UIKit -import RxSwift import RxCocoa +import RxSwift +import UIKit class BlockchainTokensView { private let viewModel: BlockchainTokensViewModel private let disposeBag = DisposeBag() - var onOpenController: ((UIViewController) -> ())? + var onOpenController: ((UIViewController) -> Void)? init(viewModel: BlockchainTokensViewModel) { self.viewModel = viewModel @@ -20,11 +20,9 @@ class BlockchainTokensView { let controller = SelectorModule.bottomMultiSelectorViewController(config: config, delegate: self) onOpenController?(controller) } - } extension BlockchainTokensView: IBottomMultiSelectorDelegate { - func bottomSelectorOnSelect(indexes: [Int]) { viewModel.onSelect(indexes: indexes) } @@ -32,5 +30,4 @@ extension BlockchainTokensView: IBottomMultiSelectorDelegate { func bottomSelectorOnCancel() { viewModel.onCancelSelect() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensViewModel.swift index b5422af7de..5e015c07ed 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BlockchainTokens/BlockchainTokensViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class BlockchainTokensViewModel { private let service: BlockchainTokensService @@ -18,26 +18,24 @@ class BlockchainTokensViewModel { let blockchain = request.blockchain let config = SelectorModule.MultiConfig( - image: .remote(url: blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), - title: blockchain.name, - description: "blockchain_settings.description".localized, - allowEmpty: request.allowEmpty, - viewItems: request.tokens.map { token in - SelectorModule.ViewItem( - title: token.type.title, - subtitle: token.type.description, - selected: request.enabledTokens.contains(token) - ) - } + image: .remote(url: blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), + title: blockchain.name, + description: "blockchain_settings.description".localized, + allowEmpty: request.allowEmpty, + viewItems: request.tokens.map { token in + SelectorModule.ViewItem( + title: token.type.title, + subtitle: token.type.description, + selected: request.enabledTokens.contains(token) + ) + } ) openBottomSelectorRelay.accept(config) } - } extension BlockchainTokensViewModel { - var openBottomSelectorSignal: Signal { openBottomSelectorRelay.asSignal() } @@ -49,5 +47,4 @@ extension BlockchainTokensViewModel { func onCancelSelect() { service.cancel() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomMultiSelectorViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomMultiSelectorViewController.swift index 1a307b4b39..9d873445db 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomMultiSelectorViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomMultiSelectorViewController.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SectionsTableView import ComponentKit +import SectionsTableView +import ThemeKit +import UIKit protocol IBottomMultiSelectorDelegate: AnyObject { func bottomSelectorOnSelect(indexes: [Int]) @@ -30,10 +30,10 @@ class BottomMultiSelectorViewController: ThemeActionSheetController { } super.init() - } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -101,41 +101,38 @@ class BottomMultiSelectorViewController: ThemeActionSheetController { doneButton.isEnabled = !currentIndexes.isEmpty } } - } extension BottomMultiSelectorViewController: SectionsDataSource { - private var descriptionRows: [RowProtocol] { guard let description = config.description else { return [] } return [ - tableView.highlightedDescriptionRow(id: "description", text: description) + tableView.highlightedDescriptionRow(id: "description", text: description), ] } func buildSections() -> [SectionProtocol] { [ Section( - id: "main", - headerState: .margin(height: config.description != nil ? 0 : .margin12), - rows: descriptionRows + config.viewItems.enumerated().map { index, viewItem in - SelectorModule.row( - viewItem: viewItem, - tableView: tableView, - isOn: currentIndexes.contains(index), - backgroundStyle: .bordered, - index: index, - isFirst: index == 0, - isLast: index == config.viewItems.count - 1 - ) { [weak self] index, isOn in - self?.onToggle(index: index, isOn: isOn) - } + id: "main", + headerState: .margin(height: config.description != nil ? 0 : .margin12), + rows: descriptionRows + config.viewItems.enumerated().map { index, viewItem in + SelectorModule.row( + viewItem: viewItem, + tableView: tableView, + isOn: currentIndexes.contains(index), + backgroundStyle: .bordered, + index: index, + isFirst: index == 0, + isLast: index == config.viewItems.count - 1 + ) { [weak self] index, isOn in + self?.onToggle(index: index, isOn: isOn) } - ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomSingleSelectorViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomSingleSelectorViewController.swift index 48a0f1195f..e31db7c2e8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomSingleSelectorViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/BottomSingleSelectorViewController.swift @@ -1,16 +1,16 @@ -import UIKit -import ThemeKit import ComponentKit import SectionsTableView +import ThemeKit +import UIKit class BottomSingleSelectorViewController: ThemeActionSheetController { private let viewItems: [SelectorModule.ViewItem] - private let onSelect: (Int) -> () + private let onSelect: (Int) -> Void private let tableView = SelfSizedSectionsTableView(style: .grouped) private let titleView = BottomSheetTitleView() - init(image: BottomSheetTitleView.Image?, title: String, subtitle: String?, viewItems: [SelectorModule.ViewItem], onSelect: @escaping (Int) -> ()) { + init(image: BottomSheetTitleView.Image?, title: String, subtitle: String?, viewItems: [SelectorModule.ViewItem], onSelect: @escaping (Int) -> Void) { self.viewItems = viewItems self.onSelect = onSelect @@ -19,7 +19,8 @@ class BottomSingleSelectorViewController: ThemeActionSheetController { titleView.bind(image: image, title: title, subtitle: subtitle, viewController: self) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -49,30 +50,27 @@ class BottomSingleSelectorViewController: ThemeActionSheetController { onSelect(index) dismiss(animated: true) } - } extension BottomSingleSelectorViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "main", - rows: viewItems.enumerated().map { index, viewItem in - SelectorModule.row( - viewItem: viewItem, - tableView: tableView, - selected: viewItem.selected, - backgroundStyle: .bordered, - index: index, - isFirst: index == 0, - isLast: index == viewItems.count - 1 - ) { [weak self] in - self?.onSelect(index: index) - } + id: "main", + rows: viewItems.enumerated().map { index, viewItem in + SelectorModule.row( + viewItem: viewItem, + tableView: tableView, + selected: viewItem.selected, + backgroundStyle: .bordered, + index: index, + isFirst: index == 0, + isLast: index == viewItems.count - 1 + ) { [weak self] in + self?.onSelect(index: index) } - ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/MultiSelectorViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/MultiSelectorViewController.swift index ec48bf541c..f1121de5b6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/MultiSelectorViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/MultiSelectorViewController.swift @@ -1,16 +1,16 @@ -import UIKit -import ThemeKit -import SectionsTableView import ComponentKit +import SectionsTableView +import ThemeKit +import UIKit class MultiSelectorViewController: ThemeViewController { private let viewItems: [SelectorModule.ViewItem] private var currentIndexes = Set() - private let onFinish: ([Int]) -> () + private let onFinish: ([Int]) -> Void private let tableView = SectionsTableView(style: .grouped) - init(title: String, viewItems: [SelectorModule.ViewItem], onFinish: @escaping ([Int]) -> ()) { + init(title: String, viewItems: [SelectorModule.ViewItem], onFinish: @escaping ([Int]) -> Void) { self.viewItems = viewItems for (index, viewItem) in viewItems.enumerated() { @@ -26,7 +26,8 @@ class MultiSelectorViewController: ThemeViewController { self.title = title } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -66,43 +67,40 @@ class MultiSelectorViewController: ThemeViewController { currentIndexes.removeAll() tableView.reload(animated: true) } - } extension MultiSelectorViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "main", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "any", - title: .body("selector.any".localized), - accessoryType: .check(currentIndexes.isEmpty), - hash: "\(currentIndexes.isEmpty)", - autoDeselect: true, - isFirst: true, - action: { [weak self] in - self?.onTapAny() - } - ) - ] + viewItems.enumerated().map { index, viewItem in - SelectorModule.row( - viewItem: viewItem, - tableView: tableView, - selected: currentIndexes.contains(index), - backgroundStyle: .lawrence, - index: index, - isLast: index == viewItems.count - 1 - ) { [weak self] in - self?.onTap(index: index) + id: "main", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( + id: "any", + title: .body("selector.any".localized), + accessoryType: .check(currentIndexes.isEmpty), + hash: "\(currentIndexes.isEmpty)", + autoDeselect: true, + isFirst: true, + action: { [weak self] in + self?.onTapAny() } + ), + ] + viewItems.enumerated().map { index, viewItem in + SelectorModule.row( + viewItem: viewItem, + tableView: tableView, + selected: currentIndexes.contains(index), + backgroundStyle: .lawrence, + index: index, + isLast: index == viewItems.count - 1 + ) { [weak self] in + self?.onTap(index: index) } - ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SelectorModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SelectorModule.swift index 4ff391a5a0..15665908c1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SelectorModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SelectorModule.swift @@ -1,21 +1,20 @@ -import UIKit import ComponentKit -import ThemeKit import SectionsTableView +import ThemeKit +import UIKit struct SelectorModule { - - static func singleSelectorViewController(title: String, viewItems: [ViewItem], onSelect: @escaping (Int) -> ()) -> UIViewController { + static func singleSelectorViewController(title: String, viewItems: [ViewItem], onSelect: @escaping (Int) -> Void) -> UIViewController { let viewController = SingleSelectorViewController(title: title, viewItems: viewItems, onSelect: onSelect) return ThemeNavigationController(rootViewController: viewController) } - static func bottomSingleSelectorViewController(image: BottomSheetTitleView.Image? = nil, title: String, subtitle: String? = nil, viewItems: [ViewItem], onSelect: @escaping (Int) -> ()) -> UIViewController { + static func bottomSingleSelectorViewController(image: BottomSheetTitleView.Image? = nil, title: String, subtitle: String? = nil, viewItems: [ViewItem], onSelect: @escaping (Int) -> Void) -> UIViewController { let viewController = BottomSingleSelectorViewController(image: image, title: title, subtitle: subtitle, viewItems: viewItems, onSelect: onSelect) return viewController.toBottomSheet } - static func multiSelectorViewController(title: String, viewItems: [ViewItem], onFinish: @escaping ([Int]) -> ()) -> UIViewController { + static func multiSelectorViewController(title: String, viewItems: [ViewItem], onFinish: @escaping ([Int]) -> Void) -> UIViewController { let viewController = MultiSelectorViewController(title: title, viewItems: viewItems, onFinish: onFinish) return ThemeNavigationController(rootViewController: viewController) } @@ -24,84 +23,80 @@ struct SelectorModule { let viewController = BottomMultiSelectorViewController(config: config, delegate: delegate) return viewController.toBottomSheet } - } extension SelectorModule { - - private static func row(viewItem: ViewItem, tableView: SectionsTableView, hash: String, accessoryElement: CellBuilderNew.CellElement, backgroundStyle: BaseThemeCell.BackgroundStyle, index: Int, isFirst: Bool = false, isLast: Bool = false, action: (() -> ())? = nil) -> RowProtocol { + private static func row(viewItem: ViewItem, tableView: SectionsTableView, hash: String, accessoryElement: CellBuilderNew.CellElement, backgroundStyle: BaseThemeCell.BackgroundStyle, index: Int, isFirst: Bool = false, isLast: Bool = false, action: (() -> Void)? = nil) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .imageElement(image: viewItem.image, size: .image32), - .vStackCentered([ - .hStack([ - .textElement(text: .body(viewItem.title, color: viewItem.titleColor), parameters: .highHugging), - .margin8, - .badge { component in - component.isHidden = viewItem.badge == nil - component.badgeView.set(style: .small) - component.badgeView.text = viewItem.badge - }, - .margin0, - .text { _ in - } - ]), - .margin(1), - .textElement(text: viewItem.subtitle.map { - .subhead2($0) - }, parameters: .truncatingMiddle), + rootElement: .hStack([ + .imageElement(image: viewItem.image, size: .image32), + .vStackCentered([ + .hStack([ + .textElement(text: .body(viewItem.title, color: viewItem.titleColor), parameters: .highHugging), + .margin8, + .badge { component in + component.isHidden = viewItem.badge == nil + component.badgeView.set(style: .small) + component.badgeView.text = viewItem.badge + }, + .margin0, + .text { _ in + }, ]), - accessoryElement + .margin(1), + .textElement(text: viewItem.subtitle.map { + .subhead2($0) + }, parameters: .truncatingMiddle), ]), - tableView: tableView, - id: "item_\(index)", - hash: hash, - height: viewItem.subtitle != nil ? .heightDoubleLineCell : (viewItem.image != nil ? .heightCell56 : .heightCell48), - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) - }, - action: action + accessoryElement, + ]), + tableView: tableView, + id: "item_\(index)", + hash: hash, + height: viewItem.subtitle != nil ? .heightDoubleLineCell : (viewItem.image != nil ? .heightCell56 : .heightCell48), + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + }, + action: action ) } - static func row(viewItem: ViewItem, tableView: SectionsTableView, selected: Bool, backgroundStyle: BaseThemeCell.BackgroundStyle, index: Int, isFirst: Bool = false, isLast: Bool = false, action: @escaping () -> ()) -> RowProtocol { + static func row(viewItem: ViewItem, tableView: SectionsTableView, selected: Bool, backgroundStyle: BaseThemeCell.BackgroundStyle, index: Int, isFirst: Bool = false, isLast: Bool = false, action: @escaping () -> Void) -> RowProtocol { row( - viewItem: viewItem, - tableView: tableView, - hash: "\(selected)", - accessoryElement: .image20 { component in - component.imageView.isHidden = !selected - component.imageView.image = UIImage(named: "check_1_20")?.withTintColor(.themeJacob) - }, - backgroundStyle: backgroundStyle, - index: index, - isFirst: isFirst, - isLast: isLast, - action: action + viewItem: viewItem, + tableView: tableView, + hash: "\(selected)", + accessoryElement: .image20 { component in + component.imageView.isHidden = !selected + component.imageView.image = UIImage(named: "check_1_20")?.withTintColor(.themeJacob) + }, + backgroundStyle: backgroundStyle, + index: index, + isFirst: isFirst, + isLast: isLast, + action: action ) } - static func row(viewItem: ViewItem, tableView: SectionsTableView, isOn: Bool, backgroundStyle: BaseThemeCell.BackgroundStyle, index: Int, isFirst: Bool = false, isLast: Bool = false, onToggle: @escaping (Int, Bool) -> ()) -> RowProtocol { + static func row(viewItem: ViewItem, tableView: SectionsTableView, isOn: Bool, backgroundStyle: BaseThemeCell.BackgroundStyle, index: Int, isFirst: Bool = false, isLast: Bool = false, onToggle: @escaping (Int, Bool) -> Void) -> RowProtocol { row( - viewItem: viewItem, - tableView: tableView, - hash: "\(isOn)", - accessoryElement: .switch { component in - component.switchView.isOn = isOn - component.onSwitch = { onToggle(index, $0) } - }, - backgroundStyle: backgroundStyle, - index: index, - isFirst: isFirst, - isLast: isLast + viewItem: viewItem, + tableView: tableView, + hash: "\(isOn)", + accessoryElement: .switch { component in + component.switchView.isOn = isOn + component.onSwitch = { onToggle(index, $0) } + }, + backgroundStyle: backgroundStyle, + index: index, + isFirst: isFirst, + isLast: isLast ) } - } extension SelectorModule { - struct MultiConfig { let image: BottomSheetTitleView.Image let title: String @@ -127,5 +122,4 @@ extension SelectorModule { self.selected = selected } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SingleSelectorViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SingleSelectorViewController.swift index 1c0725e7ca..882fb74e68 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SingleSelectorViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSelector/SingleSelectorViewController.swift @@ -1,15 +1,15 @@ -import UIKit -import ThemeKit import ComponentKit import SectionsTableView +import ThemeKit +import UIKit class SingleSelectorViewController: ThemeViewController { private let viewItems: [SelectorModule.ViewItem] - private let onSelect: (Int) -> () + private let onSelect: (Int) -> Void private let tableView = SectionsTableView(style: .grouped) - init(title: String, viewItems: [SelectorModule.ViewItem], onSelect: @escaping (Int) -> ()) { + init(title: String, viewItems: [SelectorModule.ViewItem], onSelect: @escaping (Int) -> Void) { self.viewItems = viewItems self.onSelect = onSelect @@ -18,7 +18,8 @@ class SingleSelectorViewController: ThemeViewController { self.title = title } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -47,32 +48,29 @@ class SingleSelectorViewController: ThemeViewController { onSelect(index) dismiss(animated: true) } - } extension SingleSelectorViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "main", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - SelectorModule.row( - viewItem: viewItem, - tableView: tableView, - selected: viewItem.selected, - backgroundStyle: .lawrence, - index: index, - isFirst: index == 0, - isLast: index == viewItems.count - 1 - ) { [weak self] in - self?.onSelect(index: index) - } + id: "main", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + SelectorModule.row( + viewItem: viewItem, + tableView: tableView, + selected: viewItem.selected, + backgroundStyle: .lawrence, + index: index, + isFirst: index == 0, + isLast: index == viewItems.count - 1 + ) { [weak self] in + self?.onSelect(index: index) } - ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSheet/BottomSheetViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSheet/BottomSheetViewController.swift index addb89c348..f9a372bd26 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BottomSheet/BottomSheetViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BottomSheet/BottomSheetViewController.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit import ComponentKit import SectionsTableView +import ThemeKit +import UIKit class BottomSheetViewController: ThemeActionSheetController { private let items: [BottomSheetModule.Item] @@ -24,7 +24,8 @@ class BottomSheetViewController: ThemeActionSheetController { titleView.bind(image: image, title: title, subtitle: subtitle, viewController: self) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -101,58 +102,57 @@ class BottomSheetViewController: ThemeActionSheetController { } } - private func descriptionSection(index: Int, text: String) -> SectionProtocol { Section( - id: "section-\(index)", - rows: [ - tableView.descriptionRow( - id: "description_\(index)", - text: text, - ignoreBottomMargin: true - ) - ] + id: "section-\(index)", + rows: [ + tableView.descriptionRow( + id: "description_\(index)", + text: text, + ignoreBottomMargin: true + ), + ] ) } private func highlightedDescriptionSection(index: Int, style: HighlightedDescriptionBaseView.Style = .yellow, text: String) -> SectionProtocol { Section( - id: "section-\(index)", - rows: [ - tableView.highlightedDescriptionRow( - id: "description_\(index)", - style: style, - text: text, - ignoreBottomMargin: true - ) - ] + id: "section-\(index)", + rows: [ + tableView.highlightedDescriptionRow( + id: "description_\(index)", + style: style, + text: text, + ignoreBottomMargin: true + ), + ] ) } private func copyableValueSection(index: Int, title: String, value: String) -> SectionProtocol { Section( - id: "section-\(index)", - headerState: .margin(height: .margin12), - rows: [ - CellBuilderNew.row( - rootElement: .hStack([ - .textElement(text: .body(title)), - .secondaryButton { component in - component.button.set(style: .default) - component.button.setTitle(value, for: .normal) - component.onTap = { - CopyHelper.copyAndNotify(value: value) - } - } - ]), - tableView: tableView, - id: "copyable-value-\(index)", - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .bordered, isFirst: true, isLast: true) + id: "section-\(index)", + headerState: .margin(height: .margin12), + rows: [ + CellBuilderNew.row( + rootElement: .hStack([ + .textElement(text: .body(title)), + .secondaryButton { component in + component.button.set(style: .default) + component.button.setTitle(value, for: .normal) + component.onTap = { + CopyHelper.copyAndNotify(value: value) } - ) - ] + }, + ]), + tableView: tableView, + id: "copyable-value-\(index)", + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .bordered, isFirst: true, isLast: true) + } + ), + ] ) } @@ -161,67 +161,64 @@ class BottomSheetViewController: ThemeActionSheetController { let textFont: UIFont = .subhead1 return Section( - id: "section-\(index)", - headerState: tableView.sectionHeader(text: "manage_wallets.contract_address".localized, height: 41), - rows: [ - CellBuilderNew.row( - rootElement: .hStack([ - .imageElement(image: .url(imageUrl, placeholder: "placeholder_rectangle_32"), size: .image32), - .text { component in - component.font = textFont - component.textColor = .themeLeah - component.text = value - component.numberOfLines = 0 - }, - .secondaryCircleButton { [weak self] component in - if let explorerUrl = explorerUrl { - component.isHidden = false - component.button.set(image: UIImage(named: "globe_20")) - component.onTap = { self?.open(url: explorerUrl) } - } else { - component.isHidden = true - } - } - ]), - tableView: tableView, - id: "copyable-value-\(index)", - dynamicHeight: { width in - let height = CellBuilderNew.height( - containerWidth: width, - backgroundStyle: backgroundStyle, - text: value, - font: textFont, - verticalPadding: .margin12, - elements: explorerUrl != nil ? [.fixed(width: .iconSize32), .multiline, .fixed(width: SecondaryCircleButton.size)] : [.fixed(width: .iconSize32), .multiline] - ) - - return max(height, .heightCell56) - }, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: true, isLast: true) + id: "section-\(index)", + headerState: tableView.sectionHeader(text: "manage_wallets.contract_address".localized, height: 41), + rows: [ + CellBuilderNew.row( + rootElement: .hStack([ + .imageElement(image: .url(imageUrl, placeholder: "placeholder_rectangle_32"), size: .image32), + .text { component in + component.font = textFont + component.textColor = .themeLeah + component.text = value + component.numberOfLines = 0 + }, + .secondaryCircleButton { [weak self] component in + if let explorerUrl { + component.isHidden = false + component.button.set(image: UIImage(named: "globe_20")) + component.onTap = { self?.open(url: explorerUrl) } + } else { + component.isHidden = true } - ) - ] + }, + ]), + tableView: tableView, + id: "copyable-value-\(index)", + dynamicHeight: { width in + let height = CellBuilderNew.height( + containerWidth: width, + backgroundStyle: backgroundStyle, + text: value, + font: textFont, + verticalPadding: .margin12, + elements: explorerUrl != nil ? [.fixed(width: .iconSize32), .multiline, .fixed(width: SecondaryCircleButton.size)] : [.fixed(width: .iconSize32), .multiline] + ) + + return max(height, .heightCell56) + }, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: true, isLast: true) + } + ), + ] ) } private func open(url: String) { UrlManager(inApp: true).open(url: url, from: self) } - } extension BottomSheetViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { items.enumerated().map { index, item in switch item { - case .description(let text): return descriptionSection(index: index, text: text) + case let .description(text): return descriptionSection(index: index, text: text) case let .highlightedDescription(text, style): return highlightedDescriptionSection(index: index, style: style, text: text) case let .copyableValue(title, value): return copyableValueSection(index: index, title: title, value: value) case let .contractAddress(imageUrl, value, explorerUrl): return contractAddressSection(index: index, imageUrl: imageUrl, value: value, explorerUrl: explorerUrl) } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsModule.swift index c050be5894..de4a27f3b1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsModule.swift @@ -1,12 +1,10 @@ -import SwiftUI import MarketKit +import SwiftUI struct BtcBlockchainSettingsModule { - static func view(blockchain: Blockchain) -> some View { let service = BtcBlockchainSettingsService(blockchain: blockchain, btcBlockchainManager: App.shared.btcBlockchainManager) let viewModel = BtcBlockchainSettingsViewModel(service: service) return BtcBlockchainSettingsView(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsViewModel.swift index 70c784ac33..f22b246ff4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/BtcBlockchainSettings/BtcBlockchainSettingsViewModel.swift @@ -20,19 +20,19 @@ class BtcBlockchainSettingsViewModel: ObservableObject { restoreModes = service.restoreModes.map { restoreMode in let image: BtcRestoreModeViewItem.Image switch restoreMode.restoreMode { - case .blockchair: - image = .local(name: "blockchair_32") - case .hybrid: - image = .local(name: "api_placeholder_32") - case .blockchain: - image = .remote(url: service.blockchain.type.imageUrl) + case .blockchair: + image = .local(name: "blockchair_32") + case .hybrid: + image = .local(name: "api_placeholder_32") + case .blockchain: + image = .remote(url: service.blockchain.type.imageUrl) } let description: String switch restoreMode.restoreMode { - case .blockchair: description = "btc_restore_mode.blockchair".localized - case .hybrid: description = "btc_restore_mode.hybrid".localized - case .blockchain: description = "btc_restore_mode.blockchain".localized + case .blockchair: description = "btc_restore_mode.blockchair".localized + case .hybrid: description = "btc_restore_mode.hybrid".localized + case .blockchain: description = "btc_restore_mode.blockchain".localized } return BtcRestoreModeViewItem( diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectModule.swift index c4c3ab7919..779a226729 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectModule.swift @@ -1,8 +1,7 @@ -import UIKit import ThemeKit +import UIKit struct CexCoinSelectModule { - static func viewController(mode: Mode) -> UIViewController? { guard let service = CexCoinSelectService(accountManager: App.shared.accountManager, mode: mode, cexAssetManager: App.shared.cexAssetManager) else { return nil @@ -13,14 +12,11 @@ struct CexCoinSelectModule { return ThemeNavigationController(rootViewController: viewController) } - } extension CexCoinSelectModule { - enum Mode { case deposit case withdraw } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectService.swift index 0487d1d7ae..58ac9279a6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectService.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation import HsExtensions class CexCoinSelectService { @@ -50,11 +50,9 @@ class CexCoinSelectService { lhsItem.cexAsset.coinCode.lowercased() < rhsItem.cexAsset.coinCode.lowercased() } } - } extension CexCoinSelectService { - var isEmpty: Bool { internalItems.isEmpty } @@ -63,14 +61,11 @@ extension CexCoinSelectService { self.filter = filter syncItems() } - } extension CexCoinSelectService { - struct Item { let cexAsset: CexAsset let enabled: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewController.swift index 60f39d26b1..b30b73996d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewController.swift @@ -1,9 +1,9 @@ import Combine -import UIKit -import SnapKit -import ThemeKit import ComponentKit import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class CexCoinSelectViewController: ThemeSearchViewController { private let viewModel: CexCoinSelectViewModel @@ -23,7 +23,8 @@ class CexCoinSelectViewController: ThemeSearchViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -39,9 +40,9 @@ class CexCoinSelectViewController: ThemeSearchViewController { navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) $filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.viewModel.onUpdate(filter: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.viewModel.onUpdate(filter: $0) } + .store(in: &cancellables) if viewModel.isEmpty { navigationItem.searchController = nil @@ -76,9 +77,9 @@ class CexCoinSelectViewController: ThemeSearchViewController { notFoundPlaceholder.text = "no_results_found".localized viewModel.$viewItems - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.sync(viewItems: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.sync(viewItems: $0) } + .store(in: &cancellables) sync(viewItems: viewModel.viewItems) } @@ -126,49 +127,46 @@ class CexCoinSelectViewController: ThemeSearchViewController { } } } - } extension CexCoinSelectViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "cex-assets", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - let isLast = index == viewItems.count - 1 - - return CellBuilderNew.row( - rootElement: .hStack([ - .image32 { component in - component.setImage(urlString: viewItem.imageUrl, placeholder: UIImage(named: "placeholder_circle_32")) - }, - .vStackCentered([ - .textElement(text: .body(viewItem.title)), - .margin(1), - .textElement(text: .subhead2(viewItem.subtitle)), - ]), - .badge { component in - component.isHidden = viewItem.enabled - component.badgeView.set(style: .small) - component.badgeView.text = "cex_coin_select.suspended".localized.uppercased() - } - ]), - tableView: tableView, - id: "cex-asset-\(index)", - height: .heightDoubleLineCell, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - }, - action: viewItem.enabled ? { [weak self] in - self?.onSelect(cexAsset: viewItem.cexAsset) - } : nil - ) - } - ) + id: "cex-assets", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + let isLast = index == viewItems.count - 1 + + return CellBuilderNew.row( + rootElement: .hStack([ + .image32 { component in + component.setImage(urlString: viewItem.imageUrl, placeholder: UIImage(named: "placeholder_circle_32")) + }, + .vStackCentered([ + .textElement(text: .body(viewItem.title)), + .margin(1), + .textElement(text: .subhead2(viewItem.subtitle)), + ]), + .badge { component in + component.isHidden = viewItem.enabled + component.badgeView.set(style: .small) + component.badgeView.text = "cex_coin_select.suspended".localized.uppercased() + }, + ]), + tableView: tableView, + id: "cex-asset-\(index)", + height: .heightDoubleLineCell, + bind: { cell in + cell.set(backgroundStyle: .transparent, isLast: isLast) + }, + action: viewItem.enabled ? { [weak self] in + self?.onSelect(cexAsset: viewItem.cexAsset) + } : nil + ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewModel.swift index 033de7aeb0..db01c0d588 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexCoinSelect/CexCoinSelectViewModel.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation import HsExtensions class CexCoinSelectViewModel { @@ -12,8 +12,8 @@ class CexCoinSelectViewModel { self.service = service service.$items - .sink { [weak self] in self?.sync(items: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(items: $0) } + .store(in: &cancellables) sync(items: service.items) } @@ -21,19 +21,17 @@ class CexCoinSelectViewModel { private func sync(items: [CexCoinSelectService.Item]) { viewItems = items.map { item -> ViewItem in ViewItem( - cexAsset: item.cexAsset, - title: item.cexAsset.coinCode, - subtitle: item.cexAsset.coinName, - imageUrl: item.cexAsset.coin?.imageUrl, - enabled: item.enabled + cexAsset: item.cexAsset, + title: item.cexAsset.coinCode, + subtitle: item.cexAsset.coinName, + imageUrl: item.cexAsset.coin?.imageUrl, + enabled: item.enabled ) } } - } extension CexCoinSelectViewModel { - var isEmpty: Bool { service.isEmpty } @@ -43,11 +41,9 @@ extension CexCoinSelectViewModel { self?.service.set(filter: filter?.trimmingCharacters(in: .whitespaces) ?? "") } } - } extension CexCoinSelectViewModel { - struct ViewItem { let cexAsset: CexAsset let title: String @@ -55,5 +51,4 @@ extension CexCoinSelectViewModel { let imageUrl: String? let enabled: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositModule.swift index 627d26fc9b..692e3eda0e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositModule.swift @@ -1,8 +1,7 @@ -import UIKit import ComponentKit +import UIKit struct CexDepositModule { - static func viewController(cexAsset: CexAsset) -> UIViewController? { if cexAsset.depositNetworks.isEmpty { return viewController(cexAsset: cexAsset, network: nil) @@ -18,7 +17,7 @@ struct CexDepositModule { return nil } - guard case .cex(let cexAccount) = account.type else { + guard case let .cex(cexAccount) = account.type else { return nil } @@ -28,5 +27,4 @@ struct CexDepositModule { return ReceiveAddressView(viewModel: viewModel).toViewController() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositService.swift index f81334e353..83e29824aa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositService.swift @@ -15,6 +15,7 @@ class CexDepositService { stateUpdatedSubject.send(state) } } + private let stateUpdatedSubject = PassthroughSubject, Never>() init(cexAsset: CexAsset, network: CexDepositNetwork?, provider: ICexDepositProvider) { @@ -32,31 +33,31 @@ class CexDepositService { do { let (address, memo) = try await provider.deposit(id: cexAsset.id, network: network?.id) - let minAmount = network.flatMap {network -> CoinValue? in + let minAmount = network.flatMap { network -> CoinValue? in guard network.minAmount > 0 else { return nil } return CoinValue( - kind: .cexAsset(cexAsset: cexAsset), - value: network.minAmount + kind: .cexAsset(cexAsset: cexAsset), + value: network.minAmount ) } let item = ServiceItem( - address: address, - coinCode: cexAsset.coinCode, - imageUrl: cexAsset.coin?.imageUrl, - memo: memo, - networkName: network?.name, - minAmount: minAmount + address: address, + coinCode: cexAsset.coinCode, + imageUrl: cexAsset.coin?.imageUrl, + memo: memo, + networkName: network?.name, + minAmount: minAmount ) self?.state = .completed(item) } catch { let error = ReceiveAddressModule.ErrorItem( - icon: "sync_error_48", - text: "cex_deposit.failed".localized + icon: "sync_error_48", + text: "cex_deposit.failed".localized ) { [weak self] in self?.load() } @@ -65,11 +66,9 @@ class CexDepositService { } }.store(in: &tasks) } - } extension CexDepositService: IReceiveAddressService { - var title: String { "cex_deposit.title".localized(cexAsset.coinCode) } @@ -81,11 +80,9 @@ extension CexDepositService: IReceiveAddressService { var statusUpdatedPublisher: AnyPublisher, Never> { stateUpdatedSubject.eraseToAnyPublisher() } - } extension CexDepositService { - struct Item { let address: String let coinCode: String @@ -104,5 +101,4 @@ extension CexDepositService { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositViewItemFactory.swift index ffdedbf573..d67c508c04 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDeposit/CexDepositViewItemFactory.swift @@ -3,7 +3,7 @@ import Foundation class CexDepositViewItemFactory: IReceiveAddressViewItemFactory { typealias Item = CexDepositService.Item - func viewItem(item: Item, amount: String?) -> ReceiveAddressModule.ViewItem { + func viewItem(item: Item, amount _: String?) -> ReceiveAddressModule.ViewItem { var sections = [[ReceiveAddressModule.Item]]() var viewItems = [ReceiveAddressModule.Item]() diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectModule.swift index fb59fbdcbd..6c6f5cf77d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectModule.swift @@ -1,11 +1,9 @@ import UIKit struct CexDepositNetworkSelectModule { - static func viewController(cexAsset: CexAsset) -> UIViewController { let service = CexDepositNetworkSelectService(cexAsset: cexAsset) let viewModel = CexDepositNetworkSelectViewModel(service: service) return CexDepositNetworkSelectViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectService.swift index 494e5a2375..e9393d6684 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectService.swift @@ -7,5 +7,4 @@ class CexDepositNetworkSelectService { networks = cexAsset.depositNetworks } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewController.swift index 4b163645d1..0c64a25173 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit -import ThemeKit import ComponentKit import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class CexDepositNetworkSelectViewController: ThemeViewController { private let viewModel: CexDepositNetworkSelectViewModel @@ -15,7 +15,8 @@ class CexDepositNetworkSelectViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -58,60 +59,57 @@ class CexDepositNetworkSelectViewController: ThemeViewController { navigationController?.pushViewController(viewController, animated: true) } - } extension CexDepositNetworkSelectViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "description", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.descriptionRow( - id: "description", - text: "cex_deposit_network_select.description".localized, - font: .subhead2, - textColor: .themeGray, - ignoreBottomMargin: true - ) - ] + id: "description", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.descriptionRow( + id: "description", + text: "cex_deposit_network_select.description".localized, + font: .subhead2, + textColor: .themeGray, + ignoreBottomMargin: true + ), + ] ), Section( - id: "cex-networks", - footerState: .margin(height: .margin32), - rows: viewModel.viewItems.enumerated().map { index, viewItem in - let isFirst = index == 0 - let isLast = index == viewModel.viewItems.count - 1 - - return CellBuilderNew.row( - rootElement: .hStack([ - .image32 { component in - component.setImage(urlString: viewItem.imageUrl, placeholder: UIImage(named: "placeholder_rectangle_32")) - }, - .textElement(text: .body(viewItem.title)), - .imageElement(image: viewItem.enabled ? .local(UIImage(named: "arrow_big_forward_20")) : nil, size: .image20), - .badge { component in - component.isHidden = viewItem.enabled - component.badgeView.set(style: .small) - component.badgeView.text = "cex_coin_select.suspended".localized.uppercased() - } - ]), - tableView: tableView, - id: "cex-network-\(index)", - height: .heightCell56, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) - }, - action: viewItem.enabled ? { [weak self] in - self?.onSelect(network: viewItem.network) - } : nil - ) - } - ) + id: "cex-networks", + footerState: .margin(height: .margin32), + rows: viewModel.viewItems.enumerated().map { index, viewItem in + let isFirst = index == 0 + let isLast = index == viewModel.viewItems.count - 1 + + return CellBuilderNew.row( + rootElement: .hStack([ + .image32 { component in + component.setImage(urlString: viewItem.imageUrl, placeholder: UIImage(named: "placeholder_rectangle_32")) + }, + .textElement(text: .body(viewItem.title)), + .imageElement(image: viewItem.enabled ? .local(UIImage(named: "arrow_big_forward_20")) : nil, size: .image20), + .badge { component in + component.isHidden = viewItem.enabled + component.badgeView.set(style: .small) + component.badgeView.text = "cex_coin_select.suspended".localized.uppercased() + }, + ]), + tableView: tableView, + id: "cex-network-\(index)", + height: .heightCell56, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) + }, + action: viewItem.enabled ? { [weak self] in + self?.onSelect(network: viewItem.network) + } : nil + ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewModel.swift index 3bb9535a95..eb008bf35a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexDepositNetworkSelect/CexDepositNetworkSelectViewModel.swift @@ -8,31 +8,26 @@ class CexDepositNetworkSelectViewModel { viewItems = service.networks.map { network in ViewItem( - network: network, - title: network.networkName, - imageUrl: network.blockchain?.type.imageUrl, - enabled: network.enabled + network: network, + title: network.networkName, + imageUrl: network.blockchain?.type.imageUrl, + enabled: network.enabled ) } } - } extension CexDepositNetworkSelectViewModel { - var cexAsset: CexAsset { service.cexAsset } - } extension CexDepositNetworkSelectViewModel { - struct ViewItem { let network: CexDepositNetwork let title: String let imageUrl: String? let enabled: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexAmountInputViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexAmountInputViewModel.swift index 7be957e9da..9bafbdb1f2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexAmountInputViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexAmountInputViewModel.swift @@ -1,14 +1,13 @@ import Foundation -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift protocol ICexAmountInputService: IAmountInputService { var cexAsset: CexAsset { get } } extension ICexAmountInputService { - var token: Token? { nil } @@ -16,11 +15,9 @@ extension ICexAmountInputService { var tokenObservable: Observable { .empty() } - } class CexAmountInputViewModel: AmountInputViewModel { - init(service: ICexAmountInputService, fiatService: FiatService, switchService: AmountTypeSwitchService, decimalParser: AmountDecimalParser) { super.init(service: service, fiatService: fiatService, switchService: switchService, decimalParser: decimalParser) sync(cexAsset: service.cexAsset) @@ -33,5 +30,4 @@ class CexAmountInputViewModel: AmountInputViewModel { self?.updateMaxEnabled() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexCoinService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexCoinService.swift index 829b599b7c..e38507fca3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexCoinService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexCoinService.swift @@ -1,7 +1,7 @@ -import Foundation import BigInt -import MarketKit +import Foundation import HsExtensions +import MarketKit class CexCoinService { let cexAsset: CexAsset @@ -13,11 +13,9 @@ class CexCoinService { self.currencyManager = currencyManager self.marketKit = marketKit } - } extension CexCoinService: ICoinService { - var rate: CurrencyValue? { guard let coin = cexAsset.coin else { return nil @@ -61,5 +59,4 @@ extension CexCoinService: ICoinService { func amountData(value: BigUInt, sign: FloatingPointSign = .plus) -> AmountData { amountData(value: Decimal(bigUInt: value, decimals: CexAsset.decimals) ?? 0, sign: sign) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawModule.swift index 1421e01d0d..1f855b5860 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawModule.swift @@ -1,8 +1,7 @@ -import UIKit import ThemeKit +import UIKit struct CexWithdrawModule { - static func viewController(cexAsset: CexAsset) -> UIViewController? { let networks = cexAsset.withdrawNetworks @@ -44,11 +43,9 @@ struct CexWithdrawModule { recipientViewModel: recipientViewModel ) } - } extension CexWithdrawModule { - struct SendData { let cexAsset: CexAsset let network: CexWithdrawNetwork? @@ -57,5 +54,4 @@ extension CexWithdrawModule { let feeFromAmount: Bool let fee: Decimal } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawNetworkSelectViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawNetworkSelectViewController.swift index 771c6ba117..a2c85d5b90 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawNetworkSelectViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawNetworkSelectViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit -import ThemeKit import ComponentKit import SectionsTableView +import SnapKit +import ThemeKit +import UIKit protocol ICexWithdrawNetworkSelectDelegate: AnyObject { func onSelect(index: Int) @@ -22,7 +22,8 @@ class CexWithdrawNetworkSelectViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -60,11 +61,9 @@ class CexWithdrawNetworkSelectViewController: ThemeViewController { delegate?.onSelect(index: index) dismiss(animated: true) } - } extension CexWithdrawNetworkSelectViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( @@ -78,7 +77,7 @@ extension CexWithdrawNetworkSelectViewController: SectionsDataSource { font: .subhead2, textColor: .themeGray, ignoreBottomMargin: true - ) + ), ] ), Section( @@ -99,7 +98,7 @@ extension CexWithdrawNetworkSelectViewController: SectionsDataSource { component.isHidden = viewItem.enabled component.badgeView.set(style: .small) component.badgeView.text = "cex_coin_select.suspended".localized.uppercased() - } + }, ]), tableView: tableView, id: "cex-network-\(index)", @@ -112,8 +111,7 @@ extension CexWithdrawNetworkSelectViewController: SectionsDataSource { } : nil ) } - ) + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawService.swift index da8193a095..7c962bc34e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawService.swift @@ -1,9 +1,9 @@ -import Foundation -import RxSwift -import RxCocoa -import MarketKit import Combine +import Foundation import HsExtensions +import MarketKit +import RxCocoa +import RxSwift class CexWithdrawService { private let disposeBag = DisposeBag() @@ -26,6 +26,7 @@ class CexWithdrawService { availableBalanceSubject.onNext(_availableBalance) } } + private(set) var amount: Decimal = 0 { didSet { amountSubject.onNext(amount) @@ -44,7 +45,7 @@ class CexWithdrawService { init(cexAsset: CexAsset, addressService: AddressService, selectedNetwork: CexWithdrawNetwork) { self.cexAsset = cexAsset self.addressService = addressService - self.networks = cexAsset.withdrawNetworks + networks = cexAsset.withdrawNetworks self.selectedNetwork = selectedNetwork feeFromAmount = false @@ -85,7 +86,7 @@ class CexWithdrawService { throw AmountError.minAmountViolated(coinAmount: "\(selectedNetwork.minAmount.description) \(cexAsset.coinCode)") } - if feeFromAmount && amount < fee { + if feeFromAmount, amount < fee { throw AmountError.minAmountViolated(coinAmount: "\(fee.description) \(cexAsset.coinCode)") } } @@ -105,11 +106,9 @@ class CexWithdrawService { return fee } - } extension CexWithdrawService: IAvailableBalanceService { - var availableBalance: DataStatus { .completed(_availableBalance) } @@ -117,11 +116,9 @@ extension CexWithdrawService: IAvailableBalanceService { var availableBalanceObservable: Observable> { availableBalanceSubject.asObserver().map { .completed($0) } } - } extension CexWithdrawService: ICexAmountInputService { - var balance: Decimal? { _availableBalance } @@ -138,19 +135,15 @@ extension CexWithdrawService: ICexAmountInputService { self.amount = amount syncFee() } - } extension CexWithdrawService: IErrorService { - var errorObservable: Observable { errorRelay.asObservable() } - } extension CexWithdrawService { - func setSelectNetwork(index: Int) { if let network = networks.at(index: index) { selectedNetwork = network @@ -176,7 +169,7 @@ extension CexWithdrawService { switch addressService.state { case .empty: error = AddressError.addressRequired - case .success(let address): + case let .success(address): proceedSendData = CexWithdrawModule.SendData( cexAsset: cexAsset, network: selectedNetwork, @@ -188,11 +181,9 @@ extension CexWithdrawService { default: () } } - } extension CexWithdrawService { - enum AmountError: Error, LocalizedError { case insufficientBalance case maxAmountViolated(coinAmount: String) @@ -201,8 +192,8 @@ extension CexWithdrawService { public var errorDescription: String? { switch self { case .insufficientBalance: return "cex_withdraw.error.insufficient_funds".localized - case .maxAmountViolated(let coinAmount): return "cex_withdraw.error.max_amount_violated".localized(coinAmount) - case .minAmountViolated(let coinAmount): return "cex_withdraw.error.min_amount_violated".localized(coinAmount) + case let .maxAmountViolated(coinAmount): return "cex_withdraw.error.max_amount_violated".localized(coinAmount) + case let .minAmountViolated(coinAmount): return "cex_withdraw.error.min_amount_violated".localized(coinAmount) } } } @@ -214,5 +205,4 @@ extension CexWithdrawService { "cex_withdraw.address_required".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewController.swift index dc6c754daa..272606ba68 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SectionsTableView import Combine import ComponentKit +import SectionsTableView +import ThemeKit +import UIKit class CexWithdrawViewController: ThemeViewController, ICexWithdrawNetworkSelectDelegate { private var cancellables = Set() @@ -38,7 +38,8 @@ class CexWithdrawViewController: ThemeViewController, ICexWithdrawNetworkSelectD super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -152,12 +153,9 @@ class CexWithdrawViewController: ThemeViewController, ICexWithdrawNetworkSelectD navigationController?.pushViewController(viewController, animated: true) } - } - extension CexWithdrawViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( @@ -168,7 +166,7 @@ extension CexWithdrawViewController: SectionsDataSource { cell: availableBalanceCell, id: "available-balance", height: availableBalanceCell.cellHeight - ) + ), ] ), Section( @@ -186,7 +184,7 @@ extension CexWithdrawViewController: SectionsDataSource { dynamicHeight: { [weak self] width in self?.amountCautionCell.height(containerWidth: width) ?? 0 } - ) + ), ] ), Section( @@ -203,7 +201,7 @@ extension CexWithdrawViewController: SectionsDataSource { isFirst: true, isLast: true, action: viewModel.networkViewItems.count > 1 ? { [weak self] in self?.openNetworkSelect() } : nil - ) + ), ] ), Section( @@ -223,7 +221,7 @@ extension CexWithdrawViewController: SectionsDataSource { dynamicHeight: { [weak self] width in self?.recipientCautionCell.height(containerWidth: width) ?? 0 } - ) + ), ] ), Section( @@ -241,20 +239,20 @@ extension CexWithdrawViewController: SectionsDataSource { .margin0, .text { _ in }, .vStackCentered([ - .text { [weak self] (component: TextComponent) -> () in + .text { [weak self] (component: TextComponent) in component.font = .subhead2 component.textColor = .themeLeah component.textAlignment = .right component.text = self?.fee?.coinAmount }, .margin(1), - .text { [weak self] (component: TextComponent) -> () in + .text { [weak self] (component: TextComponent) in component.font = .caption component.textColor = .themeGray component.textAlignment = .right component.text = self?.fee?.currencyAmount - } - ]) + }, + ]), ]), tableView: tableView, id: "fee-value", @@ -277,7 +275,7 @@ extension CexWithdrawViewController: SectionsDataSource { .switch { component in component.switchView.isOn = false component.onSwitch = { [weak self] in self?.onChange(feeFromAmount: $0) } - } + }, ]), tableView: tableView, id: "fee-from-amount", @@ -299,7 +297,7 @@ extension CexWithdrawViewController: SectionsDataSource { dynamicHeight: { [weak self] width in self?.warningCell.height(containerWidth: width) ?? 0 } - ) + ), ] ), Section( @@ -310,11 +308,9 @@ extension CexWithdrawViewController: SectionsDataSource { cell: buttonCell, id: "button", height: PrimaryButtonCell.height - ) + ), ] - ) + ), ] } - } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewModel.swift index df12315f68..137f4ed3e3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdraw/CexWithdrawViewModel.swift @@ -1,9 +1,9 @@ +import BigInt +import Combine import Foundation -import RxSwift -import RxCocoa import HsExtensions -import Combine -import BigInt +import RxCocoa +import RxSwift class CexWithdrawViewModel { private var cancellables = Set() @@ -20,7 +20,7 @@ class CexWithdrawViewModel { init(service: CexWithdrawService, coinService: CexCoinService) { self.service = service self.coinService = coinService - self.selectedNetwork = service.selectedNetwork.networkName + selectedNetwork = service.selectedNetwork.networkName networkViewItems = service.networks.enumerated().map { index, network in NetworkViewItem(index: index, title: network.networkName, imageUrl: network.blockchain?.type.imageUrl, enabled: network.enabled) @@ -35,7 +35,7 @@ class CexWithdrawViewModel { } private func proceed(sendData: CexWithdrawModule.SendData?) { - if let sendData = sendData { + if let sendData { proceedSubject.send(sendData) } } @@ -50,7 +50,7 @@ class CexWithdrawViewModel { } private func sync(amountError: Error?) { - var caution: Caution? = nil + var caution: Caution? if let error = amountError { caution = Caution(text: error.smartDescription, type: .error) @@ -58,11 +58,9 @@ class CexWithdrawViewModel { amountCaution = caution } - } extension CexWithdrawViewModel { - var coinCode: String { service.cexAsset.coinCode } @@ -90,11 +88,9 @@ extension CexWithdrawViewModel { func didTapProceed() { service.proceed() } - } extension CexWithdrawViewModel { - struct FeeAmount { let coinAmount: String let currencyAmount: String? @@ -106,5 +102,4 @@ extension CexWithdrawViewModel { let imageUrl: String? let enabled: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmModule.swift index 3a9f1f1ad9..c1a3d308ec 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmModule.swift @@ -1,15 +1,14 @@ +import ComponentKit import Foundation import UIKit -import ComponentKit struct CexWithdrawConfirmModule { - static func viewController(sendData: CexWithdrawModule.SendData) -> UIViewController? { guard let account = App.shared.accountManager.activeAccount else { return nil } - guard case .cex(let cexAccount) = account.type else { + guard case let .cex(cexAccount) = account.type else { return nil } @@ -23,5 +22,4 @@ struct CexWithdrawConfirmModule { let viewModel = CexWithdrawConfirmViewModel(service: service, coinService: coinService, contactLabelService: contactLabelService) return CexWithdrawConfirmViewController(viewModel: viewModel, handler: handler) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmService.swift index b97c4561cf..7ab66d17f5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmService.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation import HsExtensions class CexWithdrawConfirmService { @@ -35,11 +35,9 @@ class CexWithdrawConfirmService { var fee: Decimal { sendData.fee } - } extension CexWithdrawConfirmService { - var confirmWithdrawPublisher: AnyPublisher { confirmWithdrawSubject.eraseToAnyPublisher() } @@ -71,11 +69,9 @@ extension CexWithdrawConfirmService { self?.state = .idle }.store(in: &tasks) } - } extension CexWithdrawConfirmService { - enum State { case idle case loading @@ -84,5 +80,4 @@ extension CexWithdrawConfirmService { enum ConfirmError: Error { case invalidId } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewController.swift index e45811e1a7..88b33026ec 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewController.swift @@ -1,9 +1,9 @@ import Combine -import UIKit -import SnapKit -import ThemeKit import ComponentKit import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class CexWithdrawConfirmViewController: ThemeViewController { private let viewModel: CexWithdrawConfirmViewModel @@ -23,7 +23,8 @@ class CexWithdrawConfirmViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -60,24 +61,24 @@ class CexWithdrawConfirmViewController: ThemeViewController { withdrawingButton.setTitle("cex_withdraw_confirm.withdraw".localized, for: .normal) viewModel.$sectionViewItems - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.sync(sectionViewItems: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.sync(sectionViewItems: $0) } + .store(in: &cancellables) viewModel.$withdrawing - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.sync(withdrawing: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.sync(withdrawing: $0) } + .store(in: &cancellables) viewModel.confirmWithdrawPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.confirmWithdraw(result: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.confirmWithdraw(result: $0) } + .store(in: &cancellables) viewModel.errorPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.show(error: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.show(error: $0) } + .store(in: &cancellables) } private func sync(sectionViewItems: [CexWithdrawConfirmViewModel.SectionViewItem]) { @@ -99,10 +100,10 @@ class CexWithdrawConfirmViewController: ThemeViewController { image: .warning, title: "cex_withdraw_confirm.withdraw_failed".localized, items: [ - .highlightedDescription(text: error, style: .red) + .highlightedDescription(text: error, style: .red), ], buttons: [ - .init(style: .yellow, title: "button.ok".localized) + .init(style: .yellow, title: "button.ok".localized), ] ) @@ -116,11 +117,9 @@ class CexWithdrawConfirmViewController: ThemeViewController { @objc private func onTapWithdraw() { viewModel.onTapWithdraw() } - } extension CexWithdrawConfirmViewController: SectionsDataSource { - private func row(viewItem: CexWithdrawConfirmViewModel.ViewItem, rowInfo: RowInfo) -> RowProtocol { switch viewItem { case let .subhead(iconName, title, value): @@ -128,7 +127,7 @@ extension CexWithdrawConfirmViewController: SectionsDataSource { case let .amount(iconUrl, iconPlaceholderImageName, coinAmount, currencyAmount, type): return CellComponent.amountRow(tableView: tableView, rowInfo: rowInfo, iconUrl: iconUrl, iconPlaceholderImageName: iconPlaceholderImageName, coinAmount: coinAmount, currencyAmount: currencyAmount, type: type) case let .address(title, value, contactAddress): - var onAddToContact: (() -> ())? = nil + var onAddToContact: (() -> Void)? = nil if let contactAddress { onAddToContact = { [weak self] in ContactBookModule.showAddition(contactAddress: contactAddress, parentViewController: self) @@ -149,13 +148,12 @@ extension CexWithdrawConfirmViewController: SectionsDataSource { func buildSections() -> [SectionProtocol] { viewModel.sectionViewItems.enumerated().map { index, sectionViewItem in Section( - id: "section_\(index)", - headerState: .margin(height: index == 0 ? .margin12 : .margin16), - rows: sectionViewItem.viewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, rowInfo: RowInfo(index: index, isFirst: index == 0, isLast: index == sectionViewItem.viewItems.count - 1)) - } + id: "section_\(index)", + headerState: .margin(height: index == 0 ? .margin12 : .margin16), + rows: sectionViewItem.viewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, rowInfo: RowInfo(index: index, isFirst: index == 0, isLast: index == sectionViewItem.viewItems.count - 1)) + } ) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewModel.swift index 763a5d0b91..bc19a0c9c2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/CexWithdrawConfirm/CexWithdrawConfirmViewModel.swift @@ -21,8 +21,8 @@ class CexWithdrawConfirmViewModel { } service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) syncSectionViewItems() @@ -37,14 +37,14 @@ class CexWithdrawConfirmViewModel { private func syncSectionViewItems() { var sectionViewItems: [SectionViewItem] = [ - SectionViewItem(viewItems: mainViewItems()) + SectionViewItem(viewItems: mainViewItems()), ] if let network = service.network { sectionViewItems.append( - SectionViewItem(viewItems: [ - .value(title: "cex_withdraw_confirm.network".localized, value: network.networkName, type: .regular) - ]) + SectionViewItem(viewItems: [ + .value(title: "cex_withdraw_confirm.network".localized, value: network.networkName, type: .regular), + ]) ) } @@ -55,7 +55,7 @@ class CexWithdrawConfirmViewModel { title: "cex_withdraw.fee".localized, coinAmount: ValueFormatter.instance.formatFull(coinValue: feeData.coinValue) ?? "n/a".localized, currencyAmount: feeData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) } - ) + ), ]) ) @@ -68,22 +68,22 @@ class CexWithdrawConfirmViewModel { var viewItems: [ViewItem] = [ .subhead( - iconName: "arrow_medium_2_up_right_24", - title: "cex_withdraw_confirm.you_withdraw".localized, - value: service.cexAsset.coinName + iconName: "arrow_medium_2_up_right_24", + title: "cex_withdraw_confirm.you_withdraw".localized, + value: service.cexAsset.coinName ), .amount( - iconUrl: service.cexAsset.coin?.imageUrl, - iconPlaceholderImageName: "placeholder_circle_32", - coinAmount: ValueFormatter.instance.formatFull(coinValue: amountData.coinValue) ?? "n/a".localized, - currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, - type: .neutral + iconUrl: service.cexAsset.coin?.imageUrl, + iconPlaceholderImageName: "placeholder_circle_32", + coinAmount: ValueFormatter.instance.formatFull(coinValue: amountData.coinValue) ?? "n/a".localized, + currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, + type: .neutral ), .address( - title: "send.confirmation.to".localized, - value: service.address, - contactAddress: contactData?.contactAddress - ) + title: "send.confirmation.to".localized, + value: service.address, + contactAddress: contactData?.contactAddress + ), ] if let contactName = contactData?.name { @@ -92,27 +92,23 @@ class CexWithdrawConfirmViewModel { return viewItems } - } extension CexWithdrawConfirmViewModel { - var confirmWithdrawPublisher: AnyPublisher { service.confirmWithdrawPublisher } var errorPublisher: AnyPublisher { - service.errorPublisher.map { $0.smartDescription }.eraseToAnyPublisher() + service.errorPublisher.map(\.smartDescription).eraseToAnyPublisher() } func onTapWithdraw() { service.withdraw() } - } extension CexWithdrawConfirmViewModel { - struct SectionViewItem { let viewItems: [ViewItem] } @@ -124,5 +120,4 @@ extension CexWithdrawConfirmViewModel { case value(title: String, value: String, type: ValueType) case feeValue(title: String, coinAmount: String, currencyAmount: String?) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/RestoreCex/RestoreCexViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/RestoreCex/RestoreCexViewController.swift index 6b8d4f8406..39681ee77f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Cex/RestoreCex/RestoreCexViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Cex/RestoreCex/RestoreCexViewController.swift @@ -1,8 +1,8 @@ -import Foundation -import UIKit import ComponentKit +import Foundation import SectionsTableView import ThemeKit +import UIKit class RestoreCexViewController: ThemeViewController { private weak var returnViewController: UIViewController? @@ -15,7 +15,8 @@ class RestoreCexViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -52,47 +53,44 @@ class RestoreCexViewController: ThemeViewController { let viewController = cex.restoreViewController(returnViewController: returnViewController) navigationController?.pushViewController(viewController, animated: true) } - } extension RestoreCexViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "description", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.descriptionRow( - id: "description", - text: "restore.cex.description".localized, - font: .subhead2, - textColor: .themeGray, - ignoreBottomMargin: true - ) - ] + id: "description", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.descriptionRow( + id: "description", + text: "restore.cex.description".localized, + font: .subhead2, + textColor: .themeGray, + ignoreBottomMargin: true + ), + ] ), Section( - id: "list", - footerState: .margin(height: .margin32), - rows: Cex.allCases.enumerated().map { index, cex in - let rowInfo = RowInfo(index: index, count: Cex.allCases.count) - - return tableView.universalRow62( - id: cex.rawValue, - image: .url(cex.imageUrl), - title: .body(cex.title), - description: .subhead2(cex.url), - accessoryType: .disclosure, - isFirst: rowInfo.isFirst, - isLast: rowInfo.isLast - ) { [weak self] in - self?.openRestore(cex: cex) - } + id: "list", + footerState: .margin(height: .margin32), + rows: Cex.allCases.enumerated().map { index, cex in + let rowInfo = RowInfo(index: index, count: Cex.allCases.count) + + return tableView.universalRow62( + id: cex.rawValue, + image: .url(cex.imageUrl), + title: .body(cex.title), + description: .subhead2(cex.url), + accessoryType: .disclosure, + isFirst: rowInfo.isFirst, + isLast: rowInfo.isLast + ) { [weak self] in + self?.openRestore(cex: cex) } - ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/ChartUiView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/ChartUiView.swift index f981478619..876f0af074 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/ChartUiView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/ChartUiView.swift @@ -316,7 +316,7 @@ class ChartUiView: UIView { chartSecondaryValueLabel.isHidden = true chartSecondaryDiffLabel.isHidden = true case let .volume(value): - if let value = value { + if let value { chartSecondaryTitleLabel.isHidden = true chartSecondaryValueLabel.isHidden = false diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardTitleView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardTitleView.swift index e4dab2dea6..2e17042d0c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardTitleView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardTitleView.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit import Chart -import ThemeKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class MarketCardTitleView: UIView { private static let font: UIFont = .caption @@ -39,7 +39,8 @@ class MarketCardTitleView: UIView { badgeView.isHidden = true } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError() } @@ -60,5 +61,4 @@ class MarketCardTitleView: UIView { get { badgeView.textColor } set { badgeView.textColor = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardValueView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardValueView.swift index 0a63e83a9d..a19dd63cc0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardValueView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/Components/MarketCardValueView.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit import Chart -import ThemeKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class MarketCardValueView: UIView { private static let font: UIFont = .subhead1 @@ -37,7 +37,8 @@ class MarketCardValueView: UIView { diffLabel.font = Self.font } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError() } @@ -60,5 +61,4 @@ class MarketCardValueView: UIView { get { diffLabel.textColor } set { diffLabel.textColor = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardCell.swift index 8972481d38..6ef812d58b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardCell.swift @@ -1,9 +1,9 @@ -import UIKit -import SnapKit -import ThemeKit -import HUD import Chart import ComponentKit +import HUD +import SnapKit +import ThemeKit +import UIKit class MarketCardCell: UITableViewCell { private let stackView = UIStackView() @@ -27,24 +27,23 @@ class MarketCardCell: UITableViewCell { stackView.distribution = .fillEqually } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - func append(viewItem: MarketCardView.ViewItem, configuration: ChartConfiguration = .smallPreviewChart, onTap: (() -> ())? = nil) { + func append(viewItem: MarketCardView.ViewItem, configuration: ChartConfiguration = .smallPreviewChart, onTap: (() -> Void)? = nil) { let marketCardView = MarketCardView(configuration: configuration) marketCardView.onTap = onTap append(view: marketCardView) marketCardView.set(viewItem: viewItem) } - } extension MarketCardCell { - func append(view: UIView?) { - guard let view = view else { + guard let view else { return } @@ -76,5 +75,4 @@ extension MarketCardCell { marketCardViews.removeAll() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardView.swift index 83e20cd1d3..06d1cf3c00 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketCardView.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit import Chart -import ThemeKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class MarketCardView: UIView { static let height: CGFloat = 109 @@ -21,7 +21,7 @@ class MarketCardView: UIView { private var alreadyHasData: Bool = false - var onTap: (() -> ())? { + var onTap: (() -> Void)? { didSet { button.isUserInteractionEnabled = onTap != nil } @@ -91,7 +91,8 @@ class MarketCardView: UIView { updateUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -131,13 +132,13 @@ class MarketCardView: UIView { } var descriptionColor: UIColor! { - get { descriptionView.textColor} + get { descriptionView.textColor } set { descriptionView.textColor = newValue } } func set(chartData data: ChartData?, trend: MovementTrend?) { chartView.isHidden = data == nil - guard let data = data, let trend = trend else { + guard let data, let trend else { alreadyHasData = false return } @@ -158,7 +159,6 @@ class MarketCardView: UIView { } extension MarketCardView { - class ViewItem { let title: String? let value: String? @@ -176,8 +176,5 @@ extension MarketCardView { self.chartData = chartData self.movementTrend = movementTrend } - } - } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketWideCardCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketWideCardCell.swift index c7f330dee2..9348474f23 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketWideCardCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Chart/MarketCards/MarketWideCardCell.swift @@ -1,8 +1,8 @@ -import UIKit +import Chart +import ComponentKit import SnapKit import ThemeKit -import ComponentKit -import Chart +import UIKit class MarketWideCardCell: BaseSelectableThemeCell { private let titleLabel = UILabel() @@ -11,7 +11,7 @@ class MarketWideCardCell: BaseSelectableThemeCell { private let valueInfoLabel = UILabel() private var chartView: RateChartView? - private var onTapInfo: (() -> ())? + private var onTapInfo: (() -> Void)? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -72,7 +72,8 @@ class MarketWideCardCell: BaseSelectableThemeCell { chartView.isUserInteractionEnabled = false } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -80,7 +81,7 @@ class MarketWideCardCell: BaseSelectableThemeCell { onTapInfo?() } - func bind(title: String, value: String?, valueInfo: String?, chartData: ChartData? = nil, chartTrend: MovementTrend? = nil, chartCurveType: ChartConfiguration.CurveType = .line, onTapInfo: (() -> ())? = nil) { + func bind(title: String, value: String?, valueInfo: String?, chartData: ChartData? = nil, chartTrend: MovementTrend? = nil, chartCurveType: ChartConfiguration.CurveType = .line, onTapInfo: (() -> Void)? = nil) { titleLabel.text = title valueLabel.text = value valueInfoLabel.text = value != nil ? valueInfo : nil @@ -103,13 +104,10 @@ class MarketWideCardCell: BaseSelectableThemeCell { self.onTapInfo = onTapInfo infoButton.isHidden = onTapInfo == nil } - } extension MarketWideCardCell { - static func height(hasChart: Bool = true, bottomMargin: CGFloat = .margin16) -> CGFloat { 64 + (hasChart ? 60 + .margin12 : 0) + bottomMargin } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsHoldersCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsHoldersCell.swift index 33e358bf1e..ccf8ae5917 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsHoldersCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsHoldersCell.swift @@ -1,8 +1,8 @@ -import UIKit +import Chart +import ComponentKit import SnapKit import ThemeKit -import ComponentKit -import Chart +import UIKit class CoinAnalyticsHoldersCell: BaseThemeCell { static let chartHeight: CGFloat = 40 @@ -13,7 +13,8 @@ class CoinAnalyticsHoldersCell: BaseThemeCell { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -68,5 +69,4 @@ class CoinAnalyticsHoldersCell: BaseThemeCell { currentStackView = stackView } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsRatingScaleViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsRatingScaleViewController.swift index 1afd51e5a2..bf57a26ef2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsRatingScaleViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsRatingScaleViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit +import ComponentKit import SectionsTableView import SnapKit -import ComponentKit +import ThemeKit +import UIKit class CoinAnalyticsRatingScaleViewController: ThemeViewController { private let _title: String @@ -19,7 +19,8 @@ class CoinAnalyticsRatingScaleViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -49,46 +50,43 @@ class CoinAnalyticsRatingScaleViewController: ThemeViewController { @objc private func onClose() { dismiss(animated: true) } - } extension CoinAnalyticsRatingScaleViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "info", - footerState: .margin(height: .margin12), - rows: [ - MarkdownViewController.header1Row(id: "header", string: "coin_analytics.overall_score".localized), - MarkdownViewController.header3Row(id: "sub-header", string: _title), - MarkdownViewController.textRow(id: "description", string: _description) - ] + id: "info", + footerState: .margin(height: .margin12), + rows: [ + MarkdownViewController.header1Row(id: "header", string: "coin_analytics.overall_score".localized), + MarkdownViewController.header3Row(id: "sub-header", string: _title), + MarkdownViewController.textRow(id: "description", string: _description), + ] ), Section( - id: "items", - footerState: .margin(height: .margin32), - rows: CoinAnalyticsModule.Rating.allCases.enumerated().map { index, rating in - let isFirst = index == 0 - let isLast = index == CoinAnalyticsModule.Rating.allCases.count - 1 - - return CellBuilderNew.row( - rootElement: .hStack([ - .imageElement(image: .local(rating.image), size: .image24), - .margin8, - .textElement(text: .subhead1(rating.title.uppercased(), color: rating.color)), - .textElement(text: .subhead1(scores[rating], color: rating.color)), - ]), - tableView: tableView, - id: "rating-\(index)", - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) - } - ) - } - ) + id: "items", + footerState: .margin(height: .margin32), + rows: CoinAnalyticsModule.Rating.allCases.enumerated().map { index, rating in + let isFirst = index == 0 + let isLast = index == CoinAnalyticsModule.Rating.allCases.count - 1 + + return CellBuilderNew.row( + rootElement: .hStack([ + .imageElement(image: .local(rating.image), size: .image24), + .margin8, + .textElement(text: .subhead1(rating.title.uppercased(), color: rating.color)), + .textElement(text: .subhead1(scores[rating], color: rating.color)), + ]), + tableView: tableView, + id: "rating-\(index)", + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) + } + ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewModel.swift index 1f47b6dc51..fbf6250cd0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewModel.swift @@ -1,10 +1,10 @@ -import UIKit +import Chart import Combine -import RxSwift -import RxRelay -import RxCocoa import MarketKit -import Chart +import RxCocoa +import RxRelay +import RxSwift +import UIKit class CoinAnalyticsViewModel { private let queue = DispatchQueue(label: "\(AppConfig.label).coin_analytics_view_model", qos: .userInitiated) @@ -46,21 +46,21 @@ class CoinAnalyticsViewModel { self.coinIndicatorViewItemFactory = coinIndicatorViewItemFactory service.$state - .receive(on: queue) - .sink { [weak self] _ in self?.sync() } - .store(in: &cancellables) + .receive(on: queue) + .sink { [weak self] _ in self?.sync() } + .store(in: &cancellables) technicalIndicatorService.$state - .receive(on: queue) - .sink { [weak self] _ in self?.sync() } - .store(in: &cancellables) + .receive(on: queue) + .sink { [weak self] _ in self?.sync() } + .store(in: &cancellables) sync() } private func syncIndicators(enabled: Bool) { var loading = false - var error: Bool = false + var error = false var switchEnabled = false var viewItems = [CoinIndicatorViewItemFactory.ViewItem]() @@ -70,7 +70,7 @@ class CoinAnalyticsViewModel { case .failed: error = true switchEnabled = true - case .completed(let items): + case let .completed(items): switchEnabled = true viewItems = coinIndicatorViewItemFactory.viewItems(items: items) } @@ -97,7 +97,7 @@ class CoinAnalyticsViewModel { emptyViewRelay.accept(false) syncIndicators(enabled: false) - case .preview(let analyticsPreview): + case let .preview(analyticsPreview): let viewItem = previewViewItem(analyticsPreview: analyticsPreview) if viewItem.isEmpty { @@ -113,7 +113,7 @@ class CoinAnalyticsViewModel { syncIndicators(enabled: false) subscriptionInfoSubject.send() - case .success(let analytics): + case let .success(analytics): let viewItem = viewItem(analytics: analytics) if viewItem.isEmpty { @@ -157,9 +157,9 @@ class CoinAnalyticsViewModel { } return ChartViewItem( - value: valueString ?? "n/a".localized, - chartData: chartData, - chartTrend: first.value < last.value ? .up : .down + value: valueString ?? "n/a".localized, + chartData: chartData, + chartTrend: first.value < last.value ? .up : .down ) } @@ -169,9 +169,9 @@ class CoinAnalyticsViewModel { } return RankCardViewItem( - chart: .regular(value: chartViewItem), - rank: rank.map { .regular(value: rankString(value: $0)) }, - rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } + chart: .regular(value: chartViewItem), + rank: rank.map { .regular(value: rankString(value: $0)) }, + rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } ) } @@ -181,10 +181,10 @@ class CoinAnalyticsViewModel { } return ActiveAddressesViewItem( - chart: .regular(value: chartViewItem), - count30d: count30d.flatMap { ValueFormatter.instance.formatShort(value: Decimal($0)) }.map { .regular(value: $0) }, - rank: rank.map { .regular(value: rankString(value: $0)) }, - rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } + chart: .regular(value: chartViewItem), + count30d: count30d.flatMap { ValueFormatter.instance.formatShort(value: Decimal($0)) }.map { .regular(value: $0) }, + rank: rank.map { .regular(value: rankString(value: $0)) }, + rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } ) } @@ -194,10 +194,10 @@ class CoinAnalyticsViewModel { } return TransactionCountViewItem( - chart: .regular(value: chartViewItem), - volume: volume.flatMap { ValueFormatter.instance.formatShort(value: $0) }.map { .regular(value: [$0, coin.code].joined(separator: " ")) }, - rank: rank.map { .regular(value: rankString(value: $0)) }, - rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } + chart: .regular(value: chartViewItem), + volume: volume.flatMap { ValueFormatter.instance.formatShort(value: $0) }.map { .regular(value: [$0, coin.code].joined(separator: " ")) }, + rank: rank.map { .regular(value: rankString(value: $0)) }, + rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } ) } @@ -211,7 +211,7 @@ class CoinAnalyticsViewModel { return nil } - let blockchains = service.blockchains(uids: holderBlockchains.filter { $0.holdersCount > 0 }.map { $0.uid }) + let blockchains = service.blockchains(uids: holderBlockchains.filter { $0.holdersCount > 0 }.map(\.uid)) let items = holderBlockchains.sorted { $0.holdersCount > $1.holdersCount }.compactMap { holderBlockchain -> Item? in guard let blockchain = blockchains.first(where: { $0.uid == holderBlockchain.uid }) else { @@ -225,21 +225,21 @@ class CoinAnalyticsViewModel { return nil } - let total = items.map { $0.count }.reduce(0, +) + let total = items.map(\.count).reduce(0, +) let viewItem = HoldersViewItem( - value: ValueFormatter.instance.formatShort(value: total), - holderViewItems: items.map { item in - let percent = item.count / total - - return HolderViewItem( - blockchain: item.blockchain, - imageUrl: item.blockchain.type.imageUrl, - name: item.blockchain.name, - value: holderShareFormatter.string(from: percent as NSNumber), - percent: percent - ) - } + value: ValueFormatter.instance.formatShort(value: total), + holderViewItems: items.map { item in + let percent = item.count / total + + return HolderViewItem( + blockchain: item.blockchain, + imageUrl: item.blockchain.type.imageUrl, + name: item.blockchain.name, + value: holderShareFormatter.string(from: percent as NSNumber), + percent: percent + ) + } ) return .regular(value: viewItem) @@ -251,10 +251,10 @@ class CoinAnalyticsViewModel { } return TvlViewItem( - chart: .regular(value: chartViewItem), - rank: rank.map { .regular(value: rankString(value: $0)) }, - ratio: ratio.flatMap { ratioFormatter.string(from: $0 as NSNumber) }.map { .regular(value: $0) }, - rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } + chart: .regular(value: chartViewItem), + rank: rank.map { .regular(value: rankString(value: $0)) }, + ratio: ratio.flatMap { ratioFormatter.string(from: $0 as NSNumber) }.map { .regular(value: $0) }, + rating: rating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) } ) } @@ -264,105 +264,103 @@ class CoinAnalyticsViewModel { } return ValueRankViewItem( - value: .regular(value: formattedValue), - rank: rank.map { .regular(value: rankString(value: $0)) }, - description: description + value: .regular(value: formattedValue), + rank: rank.map { .regular(value: rankString(value: $0)) }, + description: description ) } private func viewItem(analytics: Analytics) -> ViewItem { ViewItem( - cexVolume: rankCardViewItem( - points: analytics.cexVolume?.aggregatedChartPoints.points, - value: analytics.cexVolume?.aggregatedChartPoints.aggregatedValue, - postfix: .currency, - rank: analytics.cexVolume?.rank30d, - rating: analytics.cexVolume?.rating - ), - dexVolume: rankCardViewItem( - points: analytics.dexVolume?.aggregatedChartPoints.points, - value: analytics.dexVolume?.aggregatedChartPoints.aggregatedValue, - postfix: .currency, - rank: analytics.dexVolume?.rank30d, - rating: analytics.dexVolume?.rating - ), - dexLiquidity: rankCardViewItem( - points: analytics.dexLiquidity?.chartPoints, - value: analytics.dexLiquidity?.chartPoints.last?.value, - postfix: .currency, - rank: analytics.dexLiquidity?.rank, - rating: analytics.dexLiquidity?.rating - ), - activeAddresses: activeAddressesViewItem( - points: analytics.addresses?.chartPoints, - value: analytics.addresses?.chartPoints.last?.value, - count30d: analytics.addresses?.count30d, - rank: analytics.addresses?.rank30d, - rating: analytics.addresses?.rating - ), - transactionCount: transactionCountViewItem( - points: analytics.transactions?.aggregatedChartPoints.points, - value: analytics.transactions?.aggregatedChartPoints.aggregatedValue, - volume: analytics.transactions?.volume30d, - rank: analytics.transactions?.rank30d, - rating: analytics.transactions?.rating - ), - holders: holdersViewItem(holderBlockchains: analytics.holders), - holdersRank: analytics.holdersRank.map { .regular(value: rankString(value: $0)) }, - holdersRating: analytics.holdersRating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) }, - tvl: tvlViewItem( - points: analytics.tvl?.chartPoints, - rank: analytics.tvl?.rank, - ratio: analytics.tvl?.ratio, - rating: analytics.tvl?.rating - ), - fee: valueRankViewItem( - value: analytics.fee?.value30d, - rank: analytics.fee?.rank30d, - description: analytics.fee?.description - ), - revenue: valueRankViewItem( - value: analytics.revenue?.value30d, - rank: analytics.revenue?.rank30d, - description: analytics.revenue?.description - ), - reports: analytics.reports - .map { .regular(value: "\($0)") }, - investors: analytics.fundsInvested - .flatMap { ValueFormatter.instance.formatShort(currency: service.currency, value: $0) } - .map { .regular(value: $0) }, - treasuries: analytics.treasuries - .flatMap { ValueFormatter.instance.formatShort(currency: service.currency, value: $0) } - .map { .regular(value: $0) }, - auditAddresses: service.auditAddresses - .map { .regular(value: $0) } + cexVolume: rankCardViewItem( + points: analytics.cexVolume?.aggregatedChartPoints.points, + value: analytics.cexVolume?.aggregatedChartPoints.aggregatedValue, + postfix: .currency, + rank: analytics.cexVolume?.rank30d, + rating: analytics.cexVolume?.rating + ), + dexVolume: rankCardViewItem( + points: analytics.dexVolume?.aggregatedChartPoints.points, + value: analytics.dexVolume?.aggregatedChartPoints.aggregatedValue, + postfix: .currency, + rank: analytics.dexVolume?.rank30d, + rating: analytics.dexVolume?.rating + ), + dexLiquidity: rankCardViewItem( + points: analytics.dexLiquidity?.chartPoints, + value: analytics.dexLiquidity?.chartPoints.last?.value, + postfix: .currency, + rank: analytics.dexLiquidity?.rank, + rating: analytics.dexLiquidity?.rating + ), + activeAddresses: activeAddressesViewItem( + points: analytics.addresses?.chartPoints, + value: analytics.addresses?.chartPoints.last?.value, + count30d: analytics.addresses?.count30d, + rank: analytics.addresses?.rank30d, + rating: analytics.addresses?.rating + ), + transactionCount: transactionCountViewItem( + points: analytics.transactions?.aggregatedChartPoints.points, + value: analytics.transactions?.aggregatedChartPoints.aggregatedValue, + volume: analytics.transactions?.volume30d, + rank: analytics.transactions?.rank30d, + rating: analytics.transactions?.rating + ), + holders: holdersViewItem(holderBlockchains: analytics.holders), + holdersRank: analytics.holdersRank.map { .regular(value: rankString(value: $0)) }, + holdersRating: analytics.holdersRating.flatMap { CoinAnalyticsModule.Rating(rawValue: $0) }.map { .regular(value: $0) }, + tvl: tvlViewItem( + points: analytics.tvl?.chartPoints, + rank: analytics.tvl?.rank, + ratio: analytics.tvl?.ratio, + rating: analytics.tvl?.rating + ), + fee: valueRankViewItem( + value: analytics.fee?.value30d, + rank: analytics.fee?.rank30d, + description: analytics.fee?.description + ), + revenue: valueRankViewItem( + value: analytics.revenue?.value30d, + rank: analytics.revenue?.rank30d, + description: analytics.revenue?.description + ), + reports: analytics.reports + .map { .regular(value: "\($0)") }, + investors: analytics.fundsInvested + .flatMap { ValueFormatter.instance.formatShort(currency: service.currency, value: $0) } + .map { .regular(value: $0) }, + treasuries: analytics.treasuries + .flatMap { ValueFormatter.instance.formatShort(currency: service.currency, value: $0) } + .map { .regular(value: $0) }, + auditAddresses: service.auditAddresses + .map { .regular(value: $0) } ) } private func previewViewItem(analyticsPreview data: AnalyticsPreview) -> ViewItem { ViewItem( - cexVolume: data.cexVolume ? RankCardViewItem(chart: .preview, rank: data.cexVolumeRank30d ? .preview : nil, rating: data.cexVolumeRating ? .preview : nil) : nil, - dexVolume: data.dexVolume ? RankCardViewItem(chart: .preview, rank: data.dexVolumeRank30d ? .preview : nil, rating: data.dexVolumeRating ? .preview : nil) : nil, - dexLiquidity: data.dexLiquidity ? RankCardViewItem(chart: .preview, rank: data.dexLiquidityRank ? .preview : nil, rating: data.dexLiquidityRating ? .preview : nil) : nil, - activeAddresses: data.addresses ? ActiveAddressesViewItem(chart: .preview, count30d: data.addressesCount30d ? .preview : nil, rank: data.addressesRank30d ? .preview : nil, rating: data.addressesRating ? .preview : nil) : nil, - transactionCount: data.transactions ? TransactionCountViewItem(chart: .preview, volume: data.transactionsVolume30d ? .preview : nil, rank: data.transactionsRank30d ? .preview : nil, rating: data.transactionsRating ? .preview : nil) : nil, - holders: data.holders ? .preview : nil, - holdersRank: data.holdersRank ? .preview : nil, - holdersRating: data.holdersRating ? .preview : nil, - tvl: data.tvl ? TvlViewItem(chart: .preview, rank: data.tvlRank ? .preview : nil, ratio: data.tvlRatio ? .preview : nil, rating: data.tvlRating ? .preview : nil) : nil, - fee: data.fee ? ValueRankViewItem(value: .preview, rank: data.feeRank30d ? .preview : nil, description: nil) : nil, - revenue: data.revenue ? ValueRankViewItem(value: .preview, rank: data.revenueRank30d ? .preview : nil, description: nil) : nil, - reports: data.reports ? .preview : nil, - investors: data.fundsInvested ? .preview : nil, - treasuries: data.treasuries ? .preview : nil, - auditAddresses: service.auditAddresses != nil ? .preview : nil + cexVolume: data.cexVolume ? RankCardViewItem(chart: .preview, rank: data.cexVolumeRank30d ? .preview : nil, rating: data.cexVolumeRating ? .preview : nil) : nil, + dexVolume: data.dexVolume ? RankCardViewItem(chart: .preview, rank: data.dexVolumeRank30d ? .preview : nil, rating: data.dexVolumeRating ? .preview : nil) : nil, + dexLiquidity: data.dexLiquidity ? RankCardViewItem(chart: .preview, rank: data.dexLiquidityRank ? .preview : nil, rating: data.dexLiquidityRating ? .preview : nil) : nil, + activeAddresses: data.addresses ? ActiveAddressesViewItem(chart: .preview, count30d: data.addressesCount30d ? .preview : nil, rank: data.addressesRank30d ? .preview : nil, rating: data.addressesRating ? .preview : nil) : nil, + transactionCount: data.transactions ? TransactionCountViewItem(chart: .preview, volume: data.transactionsVolume30d ? .preview : nil, rank: data.transactionsRank30d ? .preview : nil, rating: data.transactionsRating ? .preview : nil) : nil, + holders: data.holders ? .preview : nil, + holdersRank: data.holdersRank ? .preview : nil, + holdersRating: data.holdersRating ? .preview : nil, + tvl: data.tvl ? TvlViewItem(chart: .preview, rank: data.tvlRank ? .preview : nil, ratio: data.tvlRatio ? .preview : nil, rating: data.tvlRating ? .preview : nil) : nil, + fee: data.fee ? ValueRankViewItem(value: .preview, rank: data.feeRank30d ? .preview : nil, description: nil) : nil, + revenue: data.revenue ? ValueRankViewItem(value: .preview, rank: data.revenueRank30d ? .preview : nil, description: nil) : nil, + reports: data.reports ? .preview : nil, + investors: data.fundsInvested ? .preview : nil, + treasuries: data.treasuries ? .preview : nil, + auditAddresses: service.auditAddresses != nil ? .preview : nil ) } - } extension CoinAnalyticsViewModel { - var period: String { technicalIndicatorService.period.title } @@ -387,11 +385,9 @@ extension CoinAnalyticsViewModel { technicalIndicatorService.period = period } - } extension CoinAnalyticsViewModel { - var viewItemDriver: Driver { viewItemRelay.asDriver() } @@ -427,11 +423,9 @@ extension CoinAnalyticsViewModel { func onTapRetry() { service.sync() } - } extension CoinAnalyticsViewModel { - struct ViewItem { let cexVolume: RankCardViewItem? let dexVolume: RankCardViewItem? @@ -521,7 +515,6 @@ extension CoinAnalyticsViewModel { case coin case noPostfix } - } enum Previewable { @@ -538,21 +531,19 @@ enum Previewable { func previewableValue

(mapper: (T) -> P) -> Previewable

{ switch self { case .preview: return .preview - case .regular(let value): return .regular(value: mapper(value)) + case let .regular(value): return .regular(value: mapper(value)) } } func value

(mapper: (T) -> P) -> P? { switch self { case .preview: return nil - case .regular(let value): return mapper(value) + case let .regular(value): return mapper(value) } } - } extension HsPointTimePeriod { - var title: String { switch self { case .minute30, .hour8: return "" // not used @@ -562,5 +553,4 @@ extension HsPointTimePeriod { case .week1: return "coin_analytics.period.1w".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinDetailAdviceViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinDetailAdviceViewController.swift index 8069e28efd..1e981648ff 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinDetailAdviceViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinDetailAdviceViewController.swift @@ -1,10 +1,9 @@ -import UIKit import ComponentKit import SectionsTableView import ThemeKit +import UIKit class CoinDetailAdviceViewController: ThemeViewController { - private let tableView = SectionsTableView(style: .grouped) private var viewItems: [CoinIndicatorViewItemFactory.SectionDetailViewItem] @@ -14,7 +13,8 @@ class CoinDetailAdviceViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -37,34 +37,31 @@ class CoinDetailAdviceViewController: ThemeViewController { tableView.reload() } - } extension CoinDetailAdviceViewController: SectionsDataSource { - private func row(viewItem: CoinIndicatorViewItemFactory.DetailViewItem, isFirst: Bool, isLast: Bool) -> RowProtocol { tableView.universalRow48( - id: viewItem.name, - title: .subhead2(viewItem.name), - value: .subhead1(viewItem.advice, color: viewItem.color), - backgroundStyle: .lawrence, - isFirst: isFirst, - isLast: isLast + id: viewItem.name, + title: .subhead2(viewItem.name), + value: .subhead1(viewItem.advice, color: viewItem.color), + backgroundStyle: .lawrence, + isFirst: isFirst, + isLast: isLast ) } func buildSections() -> [SectionProtocol] { [Section(id: "mergin-section", headerState: .margin(height: .margin12))] + - viewItems.map { section in - Section( + viewItems.map { section in + Section( id: "header-\(section.name)", headerState: tableView.sectionHeader(text: section.name), footerState: .margin(height: .margin12), rows: section.viewItems.enumerated().map { index, item in row(viewItem: item, isFirst: index == 0, isLast: index == section.viewItems.count - 1) } - ) - } + ) + } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinIndicatorViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinIndicatorViewItemFactory.swift index 8f62fbfedd..f50922d73e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinIndicatorViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/CoinIndicatorViewItemFactory.swift @@ -1,20 +1,20 @@ +import Chart import Combine import Foundation -import UIKit -import Chart import ThemeKit +import UIKit class CoinIndicatorViewItemFactory { - static let sectionNames = ["coin_analytics.indicators.summary".localized] + ChartIndicator.Category.allCases.map { $0.title } + static let sectionNames = ["coin_analytics.indicators.summary".localized] + ChartIndicator.Category.allCases.map(\.title) private func advice(items: [TechnicalIndicatorService.Item]) -> Advice { - let rating = items.map { $0.advice.rating }.reduce(0, +) + let rating = items.map(\.advice.rating).reduce(0, +) let adviceCount = items.filter { $0.advice != .noData }.count let variations = 2 * adviceCount + 1 let baseDelta = variations / 5 let remainder = variations % 5 - let neutralAddict = remainder % 3 // how much variations will be added to neutral zone + let neutralAddict = remainder % 3 // how much variations will be added to neutral zone let sideAddict = remainder / 3 // how much will be added to sell/buy zone let deltas = [baseDelta, baseDelta + sideAddict, baseDelta + sideAddict + neutralAddict, baseDelta + sideAddict, baseDelta] @@ -22,18 +22,16 @@ class CoinIndicatorViewItemFactory { var current = -adviceCount var ranges = [Range]() for delta in deltas { - ranges.append(current..<(current + delta)) + ranges.append(current ..< (current + delta)) current += delta } let index = ranges.firstIndex { $0.contains(rating) } ?? 0 return Advice(rawValue: index) ?? .neutral } - } extension CoinIndicatorViewItemFactory { - func viewItems(items: [TechnicalIndicatorService.SectionItem]) -> [ViewItem] { var viewItems = [ViewItem]() @@ -53,16 +51,14 @@ extension CoinIndicatorViewItemFactory { func detailViewItems(items: [TechnicalIndicatorService.SectionItem]) -> [SectionDetailViewItem] { items.map { SectionDetailViewItem( - name: $0.name, - viewItems: $0.items.map { DetailViewItem(name: $0.name, advice: $0.advice.title, color: $0.advice.color) } + name: $0.name, + viewItems: $0.items.map { DetailViewItem(name: $0.name, advice: $0.advice.title, color: $0.advice.color) } ) } } - } extension CoinIndicatorViewItemFactory { - enum Advice: Int, CaseIterable { case strongSell case sell @@ -106,11 +102,9 @@ extension CoinIndicatorViewItemFactory { let name: String let viewItems: [DetailViewItem] } - } extension TechnicalIndicatorService.Advice { - var title: String { switch self { case .noData: return "coin_analytics.indicators.no_data".localized @@ -128,5 +122,4 @@ extension TechnicalIndicatorService.Advice { case .sell: return CoinIndicatorViewItemFactory.Advice.sell.color } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceCell.swift index 9b5341e479..ab703db3bd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceCell.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit import ComponentKit -import ThemeKit import HUD +import SnapKit +import ThemeKit +import UIKit class IndicatorAdviceCell: BaseThemeCell { static let height: CGFloat = 229 @@ -14,7 +14,7 @@ class IndicatorAdviceCell: BaseThemeCell { private var adviceViews = [IndicatorAdviceView]() private let spinner = HUDActivityView.create(with: .medium24) - var onTapInfo: (() -> ())? + var onTapInfo: (() -> Void)? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -50,7 +50,7 @@ class IndicatorAdviceCell: BaseThemeCell { infoButton.addTarget(self, action: #selector(onTapInfoButton), for: .touchUpInside) var lastView: UIView = headerWrapperView - for _ in 0..<3 { + for _ in 0 ..< 3 { let view = IndicatorAdviceView() adviceViews.append(view) @@ -71,18 +71,17 @@ class IndicatorAdviceCell: BaseThemeCell { spinner.set(hidden: true) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func onTapInfoButton() { onTapInfo?() } - } extension IndicatorAdviceCell { - func set(loading: Bool) { adviceViews.forEach { $0.isHidden = loading } spinner.isHidden = !loading @@ -114,5 +113,4 @@ extension IndicatorAdviceCell { view.set(advice: element.advice) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceView.swift index be904f0147..3ebe158d03 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/IndicatorAdviceView.swift @@ -1,10 +1,10 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class IndicatorAdviceView: UIView { - static private let blockHeight: CGFloat = 6 + private static let blockHeight: CGFloat = 6 private let titleLabel = UILabel() private let valueLabel = UILabel() @@ -52,7 +52,7 @@ class IndicatorAdviceView: UIView { stackView.spacing = 1 stackView.distribution = .fillEqually - for _ in 0..= i ? blockColor : blockColor.withAlphaComponent(0.2) } } - } extension IndicatorAdviceView { - func set(advice: CoinIndicatorViewItemFactory.Advice?) { valueLabel.text = advice?.title valueLabel.textColor = advice?.color ?? .themeGray @@ -95,5 +94,4 @@ extension IndicatorAdviceView { valueLabel.textColor = .themeGray updateBlocks(advice: nil) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/TechnicalIndicatorService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/TechnicalIndicatorService.swift index 0fb1291b9c..182f0b2564 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/TechnicalIndicatorService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/TechnicalIndicators/TechnicalIndicatorService.swift @@ -1,6 +1,6 @@ +import Chart import Combine import Foundation -import Chart import HsExtensions import MarketKit @@ -44,10 +44,10 @@ class TechnicalIndicatorService { Task { [weak self, marketKit, coinUid, currency, period] in do { let points = try await marketKit.chartPoints( - coinUid: coinUid, - currencyCode: currency.code, - interval: period, - pointCount: Self.pointCount + Self.additionalPoints + coinUid: coinUid, + currencyCode: currency.code, + interval: period, + pointCount: Self.pointCount + Self.additionalPoints ) self?.handle(chartPoints: points, period: period) @@ -95,7 +95,8 @@ class TechnicalIndicatorService { // Calculate cross advices let crossAdvice: Advice if let ema25 = chartData.last(name: "ema_25"), - let ema50 = chartData.last(name: "ema_50") { + let ema50 = chartData.last(name: "ema_50") + { crossAdvice = cross(ema25, ema50) } else { crossAdvice = .noData @@ -109,9 +110,9 @@ class TechnicalIndicatorService { let rsiAdvice: Advice if let rsi = chartData.last(name: "rsi") { if rsi > 70 { - rsiAdvice = .sell // overbought + rsiAdvice = .sell // overbought } else if rsi < 30 { - rsiAdvice = .buy // oversold + rsiAdvice = .buy // oversold } else { rsiAdvice = .neutral } @@ -123,7 +124,8 @@ class TechnicalIndicatorService { // Calculate MACD let macdAdvice: Advice if let macdMacd = chartData.last(name: "macd_macd"), - let macdSignal = chartData.last(name: "macd_signal") { + let macdSignal = chartData.last(name: "macd_signal") + { macdAdvice = cross(macdSignal, macdMacd) } else { macdAdvice = .noData @@ -141,7 +143,7 @@ class TechnicalIndicatorService { throw IndicatorCalculator.IndicatorError.notEnoughData } - let values = chartPoints.map { $0.value } + let values = chartPoints.map(\.value) var items = [ChartItem]() for point in chartPoints { @@ -165,11 +167,11 @@ class TechnicalIndicatorService { chartData.add(name: "rsi", values: rsiValues) } if let macdData = try? IndicatorCalculator.macd( - fast: ChartIndicatorFactory.macdPeriod[0], - long: ChartIndicatorFactory.macdPeriod[1], - signal: ChartIndicatorFactory.macdPeriod[2], - values: values) { - + fast: ChartIndicatorFactory.macdPeriod[0], + long: ChartIndicatorFactory.macdPeriod[1], + signal: ChartIndicatorFactory.macdPeriod[2], + values: values + ) { chartData.add(name: "macd_macd", values: macdData.macd) chartData.add(name: "macd_signal", values: macdData.signal) chartData.add(name: "macd_histogram", values: macdData.histogram) @@ -177,11 +179,9 @@ class TechnicalIndicatorService { return chartData } - } extension TechnicalIndicatorService { - enum Advice { case noData case buy @@ -211,5 +211,4 @@ extension TechnicalIndicatorService { let category: ChartIndicator.Category let indicatorName: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsModule.swift index 3686aae863..f8c3af8c14 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsModule.swift @@ -1,12 +1,10 @@ import UIKit struct CoinAuditsModule { - static func viewController(addresses: [String]) -> UIViewController { let service = CoinAuditsService(addresses: addresses, marketKit: App.shared.marketKit) let viewModel = CoinAuditsViewModel(service: service) let urlManager = UrlManager(inApp: true) return CoinAuditsViewController(viewModel: viewModel, urlManager: urlManager) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsService.swift index 77c1c9fab1..b61d5eae0b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsService.swift @@ -1,6 +1,6 @@ import Foundation -import MarketKit import HsExtensions +import MarketKit class CoinAuditsService { private let addresses: [String] @@ -36,33 +36,28 @@ class CoinAuditsService { let sortedReports = auditor.reports.sorted { $0.date > $1.date } return Item( - logoUrl: auditor.logoUrl, - name: auditor.name, - latestDate: sortedReports.first?.date ?? Date(timeIntervalSince1970: 0), - reports: sortedReports + logoUrl: auditor.logoUrl, + name: auditor.name, + latestDate: sortedReports.first?.date ?? Date(timeIntervalSince1970: 0), + reports: sortedReports ) } state = .completed(items.sorted { $0.latestDate > $1.latestDate }) } - } extension CoinAuditsService { - func refresh() { sync() } - } extension CoinAuditsService { - struct Item { let logoUrl: String? let name: String let latestDate: Date let reports: [AuditReport] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewController.swift index ce9e7ff323..d7fb2735a1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView import ComponentKit -import RxSwift -import RxCocoa import HUD +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class CoinAuditsViewController: ThemeViewController { private let viewModel: CoinAuditsViewModel @@ -26,7 +26,8 @@ class CoinAuditsViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -87,7 +88,7 @@ class CoinAuditsViewController: ThemeViewController { private func sync(viewItems: [CoinAuditsViewModel.ViewItem]?) { self.viewItems = viewItems - if let viewItems = viewItems { + if let viewItems { tableView.bounces = true emptyView.isHidden = !viewItems.isEmpty } else { @@ -101,17 +102,15 @@ class CoinAuditsViewController: ThemeViewController { private func open(url: String) { urlManager.open(url: url, from: self) } - } extension CoinAuditsViewController: SectionsDataSource { - private func headerRow(logoUrl: String?, name: String) -> RowProtocol { tableView.universalRow56( - id: "header-\(name)", - image: .url(logoUrl, placeholder: "placeholder_circle_32"), - title: .body(name), - backgroundStyle: .transparent + id: "header-\(name)", + image: .url(logoUrl, placeholder: "placeholder_circle_32"), + title: .body(name), + backgroundStyle: .transparent ) } @@ -120,48 +119,48 @@ extension CoinAuditsViewController: SectionsDataSource { .vStackCentered([ .textElement(text: .body(auditViewItem.date)), .margin(1), - .textElement(text: .subhead2(auditViewItem.name)) + .textElement(text: .subhead2(auditViewItem.name)), ]), - .textElement(text: .subhead1(auditViewItem.issues, color: .themeGray), parameters: .rightAlignment) + .textElement(text: .subhead1(auditViewItem.issues, color: .themeGray), parameters: .rightAlignment), ] if auditViewItem.reportUrl != nil { elements.append(contentsOf: CellBuilderNew.CellElement.accessoryElements(.disclosure)) } return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: tableView, - id: auditViewItem.name + (auditViewItem.reportUrl ?? ""), - height: .heightDoubleLineCell, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) - }, - action: auditViewItem.reportUrl.map { url in - { [weak self] in self?.open(url: url) } - } + rootElement: .hStack(elements), + tableView: tableView, + id: auditViewItem.name + (auditViewItem.reportUrl ?? ""), + height: .heightDoubleLineCell, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) + }, + action: auditViewItem.reportUrl.map { url in + { [weak self] in self?.open(url: url) } + } ) } private func poweredBySection(text: String) -> SectionProtocol { Section( - id: "powered-by", - headerState: .margin(height: .margin32), - rows: [ - Row( - id: "powered-by", - dynamicHeight: { containerWidth in - BrandFooterCell.height(containerWidth: containerWidth, title: text) - }, - bind: { cell, _ in - cell.title = text - } - ) - ] + id: "powered-by", + headerState: .margin(height: .margin32), + rows: [ + Row( + id: "powered-by", + dynamicHeight: { containerWidth in + BrandFooterCell.height(containerWidth: containerWidth, title: text) + }, + bind: { cell, _ in + cell.title = text + } + ), + ] ) } func buildSections() -> [SectionProtocol] { - guard let viewItems = viewItems, !viewItems.isEmpty else { + guard let viewItems, !viewItems.isEmpty else { return [] } @@ -170,24 +169,24 @@ extension CoinAuditsViewController: SectionsDataSource { for (index, viewItem) in viewItems.enumerated() { sections.append(contentsOf: [ Section( - id: "header-\(index)", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin8), - rows: [ - headerRow(logoUrl: viewItem.logoUrl, name: viewItem.name) - ] + id: "header-\(index)", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin8), + rows: [ + headerRow(logoUrl: viewItem.logoUrl, name: viewItem.name), + ] ), Section( - id: "audits-\(index)", - footerState: .margin(height: .margin12), - rows: viewItem.auditViewItems.enumerated().map { index, auditViewItem in - row( - auditViewItem: auditViewItem, - isFirst: index == 0, - isLast: index == viewItem.auditViewItems.count - 1 - ) - } - ) + id: "audits-\(index)", + footerState: .margin(height: .margin12), + rows: viewItem.auditViewItems.enumerated().map { index, auditViewItem in + row( + auditViewItem: auditViewItem, + isFirst: index == 0, + isLast: index == viewItem.auditViewItems.count - 1 + ) + } + ), ]) } @@ -195,5 +194,4 @@ extension CoinAuditsViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewModel.swift index d6b638a857..52beb318f3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Audits/CoinAuditsViewModel.swift @@ -1,8 +1,8 @@ import Combine -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinAuditsViewModel { private let service: CoinAuditsService @@ -16,8 +16,8 @@ class CoinAuditsViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } @@ -28,7 +28,7 @@ class CoinAuditsViewModel { viewItemsRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .completed(let items): + case let .completed(items): viewItemsRelay.accept(items.map { viewItem(item: $0) }) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -41,25 +41,23 @@ class CoinAuditsViewModel { private func auditViewItem(report: AuditReport) -> AuditViewItem { AuditViewItem( - date: DateHelper.instance.formatFullDateOnly(from: report.date), - name: report.name, - issues: "coin_analytics.audits.issues".localized + ": \(report.issues)", - reportUrl: report.link + date: DateHelper.instance.formatFullDateOnly(from: report.date), + name: report.name, + issues: "coin_analytics.audits.issues".localized + ": \(report.issues)", + reportUrl: report.link ) } private func viewItem(item: CoinAuditsService.Item) -> ViewItem { ViewItem( - logoUrl: item.logoUrl, - name: item.name, - auditViewItems: item.reports.map { auditViewItem(report: $0) } + logoUrl: item.logoUrl, + name: item.name, + auditViewItems: item.reports.map { auditViewItem(report: $0) } ) } - } extension CoinAuditsViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -75,11 +73,9 @@ extension CoinAuditsViewModel { func onTapRetry() { service.refresh() } - } extension CoinAuditsViewModel { - struct ViewItem { let logoUrl: String? let name: String @@ -92,5 +88,4 @@ extension CoinAuditsViewModel { let issues: String let reportUrl: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/ChartModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/ChartModule.swift index dfdd0e8c39..a5a3ee280c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/ChartModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/ChartModule.swift @@ -1,10 +1,9 @@ +import Chart import Foundation -import UIKit import RxCocoa -import Chart +import UIKit struct ChartModule { - struct ViewItem { let value: String? let valueDescription: String? @@ -39,7 +38,6 @@ struct ChartModule { case dominance(value: Decimal?, diff: Decimal?) case indicators(top: NSAttributedString?, bottom: NSAttributedString?) } - } enum MovementTrend { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartService.swift index fb906e3ba3..adbbba3d3a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartService.swift @@ -1,10 +1,10 @@ -import Combine -import UIKit -import RxSwift -import RxCocoa import Chart -import MarketKit +import Combine import HsExtensions +import MarketKit +import RxCocoa +import RxSwift +import UIKit protocol IChartPointFetcher { var points: DataStatus<[ChartPoint]> { get } @@ -21,7 +21,7 @@ class CoinChartService { private let indicatorRepository: IChartIndicatorsRepository private let coinUid: String - private let indicatorsShownUpdatedRelay = PublishRelay<()>() + private let indicatorsShownUpdatedRelay = PublishRelay() var indicatorsShown: Bool { get { localStorage.indicatorsShown @@ -52,7 +52,7 @@ class CoinChartService { } } - private let intervalsUpdatedRelay = PublishRelay<()>() + private let intervalsUpdatedRelay = PublishRelay() private(set) var startTime: TimeInterval? { didSet { if startTime != oldValue { @@ -73,10 +73,10 @@ class CoinChartService { periodType = .byCustomPoints(.day1, indicatorRepository.extendedPointCount) indicatorRepository.updatedPublisher - .sink { [weak self] in - self?.fetchWithUpdatedIndicators() - } - .store(in: &cancellables) + .sink { [weak self] in + self?.fetchWithUpdatedIndicators() + } + .store(in: &cancellables) } private func fetchStartTime() { @@ -101,7 +101,7 @@ class CoinChartService { } private func handle(fromTimestamp: TimeInterval, chartPoints: [ChartPoint], periodType: HsPeriodType) { - guard chartPoints.count >= 2, let firstPoint = chartPoints.first(where: { $0.timestamp >= fromTimestamp}), let lastPoint = chartPoints.last else { + guard chartPoints.count >= 2, let firstPoint = chartPoints.first(where: { $0.timestamp >= fromTimestamp }), let lastPoint = chartPoints.last else { state = .failed(ChartError.notEnoughPoints) return } @@ -116,30 +116,28 @@ class CoinChartService { } let item = Item( - coinUid: coinUid, - rate: coinPrice.value, - rateDiff24h: coinPrice.diff, - timestamp: coinPrice.timestamp, - chartPointsItem: chartPointsItem, - indicators: indicatorRepository.indicators + coinUid: coinUid, + rate: coinPrice.value, + rateDiff24h: coinPrice.diff, + timestamp: coinPrice.timestamp, + chartPointsItem: chartPointsItem, + indicators: indicatorRepository.indicators ) state = .completed(item) } - } extension CoinChartService { - var periodTypeObservable: Observable { periodTypeRelay.asObservable() } - var indicatorsShownUpdatedObservable: Observable<()> { + var indicatorsShownUpdatedObservable: Observable { indicatorsShownUpdatedRelay.asObservable() } - var intervalsUpdatedObservable: Observable<()> { + var intervalsUpdatedObservable: Observable { intervalsUpdatedRelay.asObservable() } @@ -161,7 +159,7 @@ extension CoinChartService { func fetchWithUpdatedIndicators() { switch periodType { - case .byCustomPoints(let interval, _): + case let .byCustomPoints(interval, _): let updatedType: HsPeriodType = .byCustomPoints(interval, indicatorRepository.extendedPointCount) if periodType == updatedType { fetch() @@ -180,11 +178,11 @@ extension CoinChartService { coinPrice = marketKit.coinPrice(coinUid: coinUid, currencyCode: currency.code) marketKit.coinPricePublisher(tag: "coin-chart-service", coinUid: coinUid, currencyCode: currency.code) - .sink { [weak self] coinPrice in - self?.coinPrice = coinPrice - self?.syncState() - } - .store(in: &cancellables) + .sink { [weak self] coinPrice in + self?.coinPrice = coinPrice + self?.syncState() + } + .store(in: &cancellables) fetch() } @@ -203,23 +201,19 @@ extension CoinChartService { fetchChartInfo() } } - } extension CoinChartService: IChartPointFetcher { - var points: DataStatus<[ChartPoint]> { state.map { item in item.chartPointsItem.points } } - var pointsUpdatedPublisher: AnyPublisher<(), Never> { + var pointsUpdatedPublisher: AnyPublisher { stateUpdatedSubject.eraseToAnyPublisher() } - } extension CoinChartService { - struct Item { let coinUid: String let rate: Decimal @@ -238,5 +232,4 @@ extension CoinChartService { enum ChartError: Error { case notEnoughPoints } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartViewModel.swift index 3d0587a45e..78839f3104 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChart/CoinChartViewModel.swift @@ -1,11 +1,11 @@ -import Foundation -import RxSwift -import RxRelay -import RxCocoa -import MarketKit import Chart -import HUD import Combine +import Foundation +import HUD +import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinChartViewModel: ObservableObject { private let service: CoinChartService @@ -22,12 +22,12 @@ class CoinChartViewModel: ObservableObject { private let chartInfoRelay = BehaviorRelay(value: nil) private let errorRelay = BehaviorRelay(value: false) private let indicatorsShownRelay = BehaviorRelay(value: true) - private let openSettingsRelay = PublishRelay<()>() + private let openSettingsRelay = PublishRelay() @Published private(set) var indicatorsShown: Bool var intervals: [String] { - service.validIntervals.map { $0.title } + ["chart.time_duration.all".localized] + service.validIntervals.map(\.title) + ["chart.time_duration.all".localized] } init(service: CoinChartService, factory: CoinChartFactory) { @@ -58,7 +58,7 @@ class CoinChartViewModel: ObservableObject { private func index(periodType: HsPeriodType) -> Int { switch periodType { case .byStartTime: return service.validIntervals.count - case .byPeriod(let interval), .byCustomPoints(let interval, _): return service.validIntervals.firstIndex(of: interval) ?? 0 + case let .byPeriod(interval), let .byCustomPoints(interval, _): return service.validIntervals.firstIndex(of: interval) ?? 0 } } @@ -75,18 +75,16 @@ class CoinChartViewModel: ObservableObject { loadingRelay.accept(false) errorRelay.accept(true) chartInfoRelay.accept(nil) - case .completed(let item): + case let .completed(item): loadingRelay.accept(false) errorRelay.accept(false) let convert = factory.convert(item: item, periodType: service.periodType, currency: service.currency) chartInfoRelay.accept(convert) } } - } extension CoinChartViewModel: IChartViewModel { - var pointSelectedItemDriver: Driver { pointSelectedItemRelay.asDriver() } @@ -115,7 +113,7 @@ extension CoinChartViewModel: IChartViewModel { indicatorsShownRelay.asDriver() } - var openSettingsSignal: Signal<()> { + var openSettingsSignal: Signal { openSettingsRelay.asSignal() } @@ -150,35 +148,30 @@ extension CoinChartViewModel: IChartViewModel { func onToggleIndicators() { service.indicatorsShown.toggle() } - } extension CoinChartViewModel: IChartViewTouchDelegate { - - public func touchDown() { - } + public func touchDown() {} public func select(item: ChartItem, indicators: [ChartIndicator]) { HapticGenerator.instance.notification(.feedback(.soft)) pointSelectedItemRelay.accept( - factory.selectedPointViewItem( - chartItem: item, - indicators: indicators, - firstChartItem: chartInfoRelay.value?.chartData.visibleItems.first, - currency: service.currency - ) + factory.selectedPointViewItem( + chartItem: item, + indicators: indicators, + firstChartItem: chartInfoRelay.value?.chartData.visibleItems.first, + currency: service.currency + ) ) } public func touchUp() { pointSelectedItemRelay.accept(nil) } - } extension HsTimePeriod { - var title: String { switch self { case .day1: return "chart.time_duration.day".localized @@ -191,5 +184,4 @@ extension HsTimePeriod { case .year2: return "chart.time_duration.year2".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChartFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChartFactory.swift index e7b69a2286..126e9551a1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChartFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinChartFactory.swift @@ -1,7 +1,7 @@ -import Foundation -import UIKit import Chart +import Foundation import MarketKit +import UIKit class CoinChartFactory { private let dateFormatter = DateFormatter() @@ -50,28 +50,26 @@ class CoinChartFactory { return item } - let values = points.map { - $0.value - } + let values = points.map(\.value) return ChartModule.ViewItem( - value: ValueFormatter.instance.formatFull(currencyValue: CurrencyValue(currency: currency, value: item.rate)), - valueDescription: nil, - rightSideMode: .none, - chartData: ChartData(items: items, startWindow: firstPoint.timestamp, endWindow: lastPoint.timestamp), - indicators: item.indicators, - chartTrend: lastPoint.value > firstPoint.value ? .up : .down, - chartDiff: (lastPoint.value - firstPoint.value) / firstPoint.value * 100, - minValue: values.min().flatMap { - ValueFormatter.instance.formatFull(currency: currency, value: $0) - }, - maxValue: values.max().flatMap { - ValueFormatter.instance.formatFull(currency: currency, value: $0) - } + value: ValueFormatter.instance.formatFull(currencyValue: CurrencyValue(currency: currency, value: item.rate)), + valueDescription: nil, + rightSideMode: .none, + chartData: ChartData(items: items, startWindow: firstPoint.timestamp, endWindow: lastPoint.timestamp), + indicators: item.indicators, + chartTrend: lastPoint.value > firstPoint.value ? .up : .down, + chartDiff: (lastPoint.value - firstPoint.value) / firstPoint.value * 100, + minValue: values.min().flatMap { + ValueFormatter.instance.formatFull(currency: currency, value: $0) + }, + maxValue: values.max().flatMap { + ValueFormatter.instance.formatFull(currency: currency, value: $0) + } ) } - func selectedPointViewItem(chartItem: ChartItem, indicators: [ChartIndicator], firstChartItem: ChartItem?, currency: Currency) -> ChartModule.SelectedPointViewItem? { + func selectedPointViewItem(chartItem: ChartItem, indicators: [ChartIndicator], firstChartItem _: ChartItem?, currency: Currency) -> ChartModule.SelectedPointViewItem? { guard let rate = chartItem.indicators[ChartData.rate] else { return nil } @@ -90,21 +88,21 @@ class CoinChartFactory { } let visibleMaIndicators = indicators - .filter { - $0.onChart && $0.enabled - } - .compactMap { - $0 as? MaIndicator - } + .filter { + $0.onChart && $0.enabled + } + .compactMap { + $0 as? MaIndicator + } let visibleBottomIndicators = indicators - .filter { - !$0.onChart && $0.enabled - } + .filter { + !$0.onChart && $0.enabled + } let rightSideMode: ChartModule.RightSideMode // If no any visible indicators, we show only volume - if visibleMaIndicators.isEmpty && visibleBottomIndicators.isEmpty { + if visibleMaIndicators.isEmpty, visibleBottomIndicators.isEmpty { rightSideMode = .volume(value: volumeString) } else { let maPairs = visibleMaIndicators.compactMap { ma -> (Decimal, UIColor)? in @@ -117,7 +115,7 @@ class CoinChartFactory { } // build top-line string let topLineString = NSMutableAttributedString() - let paragraphStyle: NSMutableParagraphStyle = NSMutableParagraphStyle() + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = NSTextAlignment.right for (index, pair) in maPairs.enumerated() { @@ -169,9 +167,9 @@ class CoinChartFactory { } return ChartModule.SelectedPointViewItem( - value: formattedValue, - date: formattedDate, - rightSideMode: rightSideMode + value: formattedValue, + date: formattedDate, + rightSideMode: rightSideMode ) } @@ -182,34 +180,31 @@ class CoinChartFactory { // try to split interval by 4 chunks switch hoursCount { - case 120...Int.max: return hoursCount / 4 - case 60..<120: return 24 - case 28..<60: return 12 + case 120 ... Int.max: return hoursCount / 4 + case 60 ..< 120: return 24 + case 28 ..< 60: return 12 default: return 4 } } - } extension HsPeriodType { - public func `in`(_ intervals: [HsTimePeriod]) -> Bool { switch self { - case .byPeriod(let interval): return intervals.contains(interval) - case .byCustomPoints(let interval, _): return intervals.contains(interval) + case let .byPeriod(interval): return intervals.contains(interval) + case let .byCustomPoints(interval, _): return intervals.contains(interval) case .byStartTime: return false } } var gridInterval: Int { switch self { - case .byPeriod(let interval): + case let .byPeriod(interval): return ChartIntervalConverter.convert(interval: interval) - case .byCustomPoints(let interval, _): + case let .byCustomPoints(interval, _): return ChartIntervalConverter.convert(interval: interval) - case .byStartTime(let startTime): + case let .byStartTime(startTime): return CoinChartFactory.gridInterval(fromTimestamp: startTime) } } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift index 2a2733b64a..642c8060ee 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift @@ -1,11 +1,9 @@ import UIKit struct CoinInvestorsModule { - static func viewController(coinUid: String) -> UIViewController { let service = CoinInvestorsService(coinUid: coinUid, marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager) let viewModel = CoinInvestorsViewModel(service: service) return CoinInvestorsViewController(viewModel: viewModel, urlManager: UrlManager(inApp: true)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift index b9b199171d..e92bfa9b1b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift class CoinInvestorsService { private let coinUid: String @@ -33,11 +33,9 @@ class CoinInvestorsService { } }.store(in: &tasks) } - } extension CoinInvestorsService { - var usdCurrency: Currency { let currencies = currencyManager.currencies return currencies.first { $0.code == "USD" } ?? currencies[0] @@ -46,5 +44,4 @@ extension CoinInvestorsService { func refresh() { sync() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift index 92e05db720..1fc7b4f4fc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift @@ -1,12 +1,12 @@ +import ComponentKit import Foundation -import UIKit -import RxSwift +import HUD import RxCocoa +import RxSwift +import SectionsTableView import SnapKit import ThemeKit -import SectionsTableView -import ComponentKit -import HUD +import UIKit class CoinInvestorsViewController: ThemeViewController { private let viewModel: CoinInvestorsViewModel @@ -26,7 +26,8 @@ class CoinInvestorsViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -83,55 +84,53 @@ class CoinInvestorsViewController: ThemeViewController { tableView.reload() } - } extension CoinInvestorsViewController: SectionsDataSource { - private func headerSection(index: Int, title: String, value: String) -> SectionProtocol { Section( - id: "header-\(index)", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin12), - rows: [ - tableView.universalRow48( - id: "header-\(index)", - title: .body(title, color: .themeJacob), - value: .body(value), - backgroundStyle: .transparent - ) - ] + id: "header-\(index)", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin12), + rows: [ + tableView.universalRow48( + id: "header-\(index)", + title: .body(title, color: .themeJacob), + value: .body(value), + backgroundStyle: .transparent + ), + ] ) } private func row(fundViewItem: CoinInvestorsViewModel.FundViewItem, isFirst: Bool, isLast: Bool) -> RowProtocol { tableView.universalRow56( - id: fundViewItem.uid, - image: .url(fundViewItem.logoUrl, placeholder: "placeholder_circle_32"), - title: .body(fundViewItem.name), - value: fundViewItem.isLead ? .subhead1("coin_analytics.funding.lead".localized, color: .themeRemus) : nil, - accessoryType: fundViewItem.url.isEmpty ? .none : .disclosure, - autoDeselect: true, - isFirst: isFirst, - isLast: isLast, - action: { [weak self] in - self?.urlManager.open(url: fundViewItem.url, from: self) - } + id: fundViewItem.uid, + image: .url(fundViewItem.logoUrl, placeholder: "placeholder_circle_32"), + title: .body(fundViewItem.name), + value: fundViewItem.isLead ? .subhead1("coin_analytics.funding.lead".localized, color: .themeRemus) : nil, + accessoryType: fundViewItem.url.isEmpty ? .none : .disclosure, + autoDeselect: true, + isFirst: isFirst, + isLast: isLast, + action: { [weak self] in + self?.urlManager.open(url: fundViewItem.url, from: self) + } ) } private func section(index: Int, fundViewItems: [CoinInvestorsViewModel.FundViewItem], isLast: Bool) -> SectionProtocol { Section( - id: "section-\(index)", - footerState: .margin(height: isLast ? .margin32 : 0), - rows: fundViewItems.enumerated().map { index, fundViewItem in - row(fundViewItem: fundViewItem, isFirst: index == 0, isLast: index == fundViewItems.count - 1) - } + id: "section-\(index)", + footerState: .margin(height: isLast ? .margin32 : 0), + rows: fundViewItems.enumerated().map { index, fundViewItem in + row(fundViewItem: fundViewItem, isFirst: index == 0, isLast: index == fundViewItems.count - 1) + } ) } func buildSections() -> [SectionProtocol] { - guard let viewItems = viewItems else { + guard let viewItems else { return [] } @@ -144,5 +143,4 @@ extension CoinInvestorsViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift index 91ccd609bb..13fef8ed77 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift @@ -1,8 +1,8 @@ import Combine -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinInvestorsViewModel { private let service: CoinInvestorsService @@ -16,8 +16,8 @@ class CoinInvestorsViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } @@ -28,7 +28,7 @@ class CoinInvestorsViewModel { viewItemsRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .completed(let investments): + case let .completed(investments): viewItemsRelay.accept(investments.map { viewItem(investment: $0) }) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -41,26 +41,24 @@ class CoinInvestorsViewModel { private func viewItem(investment: CoinInvestment) -> ViewItem { ViewItem( - amount: investment.amount.flatMap { ValueFormatter.instance.formatShort(currency: service.usdCurrency, value: $0) } ?? "---", - info: "\(investment.round) - \(DateHelper.instance.formatFullDateOnly(from: investment.date))", - fundViewItems: investment.funds.map { fundViewItem(fund: $0) } + amount: investment.amount.flatMap { ValueFormatter.instance.formatShort(currency: service.usdCurrency, value: $0) } ?? "---", + info: "\(investment.round) - \(DateHelper.instance.formatFullDateOnly(from: investment.date))", + fundViewItems: investment.funds.map { fundViewItem(fund: $0) } ) } private func fundViewItem(fund: CoinInvestment.Fund) -> FundViewItem { FundViewItem( - uid: fund.uid, - name: fund.name, - logoUrl: fund.logoUrl, - isLead: fund.isLead, - url: fund.website + uid: fund.uid, + name: fund.name, + logoUrl: fund.logoUrl, + isLead: fund.isLead, + url: fund.website ) } - } extension CoinInvestorsViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -76,11 +74,9 @@ extension CoinInvestorsViewModel { func onTapRetry() { service.refresh() } - } extension CoinInvestorsViewModel { - struct ViewItem { let amount: String let info: String @@ -94,5 +90,4 @@ extension CoinInvestorsViewModel { let isLead: Bool let url: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHolderChartCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHolderChartCell.swift index e26c3857a5..1da3ba82b9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHolderChartCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHolderChartCell.swift @@ -1,6 +1,6 @@ import ComponentKit -import ThemeKit import SnapKit +import ThemeKit import UIKit class CoinMajorHolderChartCell: BaseThemeCell { @@ -42,7 +42,8 @@ class CoinMajorHolderChartCell: BaseThemeCell { descriptionLabel.text = "coin_analytics.holders.in_top_10_addresses".localized } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -50,5 +51,4 @@ class CoinMajorHolderChartCell: BaseThemeCell { percentLabel.text = percent countLabel.text = count.map { "coin_analytics.holders.count".localized($0) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersModule.swift index 6592d32082..75d7ec9f9c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersModule.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit struct CoinMajorHoldersModule { - static func viewController(coin: Coin, blockchain: Blockchain) -> UIViewController { let service = CoinMajorHoldersService(coin: coin, blockchain: blockchain, marketKit: App.shared.marketKit, evmLabelManager: App.shared.evmLabelManager) let viewModel = CoinMajorHoldersViewModel(service: service) @@ -12,5 +11,4 @@ struct CoinMajorHoldersModule { return ThemeNavigationController(rootViewController: viewController) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersService.swift index 558ce83c2d..15ba5625a2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersService.swift @@ -1,5 +1,5 @@ -import MarketKit import HsExtensions +import MarketKit class CoinMajorHoldersService { let coin: Coin @@ -33,11 +33,9 @@ class CoinMajorHoldersService { } }.store(in: &tasks) } - } extension CoinMajorHoldersService { - func labeled(address: String) -> String { evmLabelManager.mapped(address: address) } @@ -45,5 +43,4 @@ extension CoinMajorHoldersService { func refresh() { sync() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewController.swift index 9a1060fe7f..7d87116705 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewController.swift @@ -1,12 +1,12 @@ -import Foundation -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView import ComponentKit -import RxSwift -import RxCocoa +import Foundation import HUD +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class CoinMajorHoldersViewController: ThemeViewController { private let viewModel: CoinMajorHoldersViewModel @@ -26,7 +26,8 @@ class CoinMajorHoldersViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -88,43 +89,41 @@ class CoinMajorHoldersViewController: ThemeViewController { tableView.isHidden = stateViewItem == nil tableView.reload() } - } extension CoinMajorHoldersViewController: SectionsDataSource { - private func row(viewItem: CoinMajorHoldersViewModel.ViewItem, isLast: Bool) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .text { component in - component.font = .captionSB - component.textColor = .themeGray - component.text = viewItem.order - component.textAlignment = .center - - component.snp.remakeConstraints { maker in - maker.width.equalTo(24) - } - }, - .vStackCentered([ - .textElement(text: .body(viewItem.percent)), - .margin(1), - .textElement(text: .subhead2(viewItem.quantity)) - ]), - .secondaryButton { component in - component.button.set(style: .default) - component.button.setTitle(viewItem.labeledAddress, for: .normal) - component.onTap = { - CopyHelper.copyAndNotify(value: viewItem.address) - } + rootElement: .hStack([ + .text { component in + component.font = .captionSB + component.textColor = .themeGray + component.text = viewItem.order + component.textAlignment = .center + + component.snp.remakeConstraints { maker in + maker.width.equalTo(24) } + }, + .vStackCentered([ + .textElement(text: .body(viewItem.percent)), + .margin(1), + .textElement(text: .subhead2(viewItem.quantity)), ]), - tableView: tableView, - id: viewItem.order, - height: 62, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - } + .secondaryButton { component in + component.button.set(style: .default) + component.button.setTitle(viewItem.labeledAddress, for: .normal) + component.onTap = { + CopyHelper.copyAndNotify(value: viewItem.address) + } + }, + ]), + tableView: tableView, + id: viewItem.order, + height: 62, + bind: { cell in + cell.set(backgroundStyle: .transparent, isLast: isLast) + } ) } @@ -137,71 +136,69 @@ extension CoinMajorHoldersViewController: SectionsDataSource { var sections: [SectionProtocol] = [ Section( - id: "info", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin12), - rows: [ - Row( - id: "info", - height: CoinMajorHolderChartCell.height, - bind: { cell, _ in - cell.set(backgroundStyle: .transparent, isFirst: true) - cell.bind(percent: stateViewItem.percent, count: stateViewItem.holdersCount) - } - ), - - ] + id: "info", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin12), + rows: [ + Row( + id: "info", + height: CoinMajorHolderChartCell.height, + bind: { cell, _ in + cell.set(backgroundStyle: .transparent, isFirst: true) + cell.bind(percent: stateViewItem.percent, count: stateViewItem.holdersCount) + } + ), + ] ), Section( - id: "chart", - footerState: .margin(height: .margin24), - rows: [ - Row( - id: "holders-pie", - height: CoinAnalyticsHoldersCell.chartHeight, - bind: { cell, _ in - cell.set(backgroundStyle: .transparent, isFirst: true) - - cell.bind(items: [ - (stateViewItem.totalPercent, chartColor), - (stateViewItem.remainingPercent, chartColor.withAlphaComponent(0.5)) - ]) - } - ) - ] + id: "chart", + footerState: .margin(height: .margin24), + rows: [ + Row( + id: "holders-pie", + height: CoinAnalyticsHoldersCell.chartHeight, + bind: { cell, _ in + cell.set(backgroundStyle: .transparent, isFirst: true) + + cell.bind(items: [ + (stateViewItem.totalPercent, chartColor), + (stateViewItem.remainingPercent, chartColor.withAlphaComponent(0.5)), + ]) + } + ), + ] ), Section( - id: "holders", - footerState: .margin(height: .margin32), - rows: stateViewItem.viewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, isLast: index == stateViewItem.viewItems.count - 1) - } - ) + id: "holders", + footerState: .margin(height: .margin32), + rows: stateViewItem.viewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, isLast: index == stateViewItem.viewItems.count - 1) + } + ), ] if let url = stateViewItem.holdersUrl { sections.append( - Section( + Section( + id: "url", + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( id: "url", - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "url", - title: .body("coin_analytics.holders.see_all".localized), - accessoryType: .disclosure, - autoDeselect: true, - isFirst: true, - isLast: true, - action: { [weak self] in - self?.urlManager.open(url: url, from: self) - } - ) - ] - ) + title: .body("coin_analytics.holders.see_all".localized), + accessoryType: .disclosure, + autoDeselect: true, + isFirst: true, + isLast: true, + action: { [weak self] in + self?.urlManager.open(url: url, from: self) + } + ), + ] + ) ) } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewModel.swift index 485f8776a5..14ac783741 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMajorHolders/CoinMajorHoldersViewModel.swift @@ -1,9 +1,9 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import RxCocoa +import Foundation import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinMajorHoldersViewModel { private let service: CoinMajorHoldersService @@ -26,8 +26,8 @@ class CoinMajorHoldersViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } @@ -38,7 +38,7 @@ class CoinMajorHoldersViewModel { stateViewItemRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .completed(let tokenHolders): + case let .completed(tokenHolders): stateViewItemRelay.accept(stateViewItem(tokenHolders: tokenHolders)) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -54,33 +54,31 @@ class CoinMajorHoldersViewModel { let viewItems = tokenHolders.topHolders.enumerated().map { index, item in ViewItem( - order: "\(index + 1)", - percent: percentFormatter.string(from: (item.percentage / 100) as NSNumber), - quantity: ValueFormatter.instance.formatShort(value: item.balance, decimalCount: 0, symbol: service.coin.code), - labeledAddress: service.labeled(address: item.address), - address: item.address + order: "\(index + 1)", + percent: percentFormatter.string(from: (item.percentage / 100) as NSNumber), + quantity: ValueFormatter.instance.formatShort(value: item.balance, decimalCount: 0, symbol: service.coin.code), + labeledAddress: service.labeled(address: item.address), + address: item.address ) } - let totalPercent = tokenHolders.topHolders.map { $0.percentage }.reduce(0, +) + let totalPercent = tokenHolders.topHolders.map(\.percentage).reduce(0, +) percentFormatter.maximumFractionDigits = 2 let percent = percentFormatter.string(from: (totalPercent / 100) as NSNumber) return StateViewItem( - holdersCount: ValueFormatter.instance.formatShort(value: tokenHolders.count), - totalPercent: totalPercent, - remainingPercent: 100.0 - totalPercent, - percent: percent, - viewItems: viewItems, - holdersUrl: tokenHolders.holdersUrl + holdersCount: ValueFormatter.instance.formatShort(value: tokenHolders.count), + totalPercent: totalPercent, + remainingPercent: 100.0 - totalPercent, + percent: percent, + viewItems: viewItems, + holdersUrl: tokenHolders.holdersUrl ) } - } extension CoinMajorHoldersViewModel { - var stateViewItemDriver: Driver { stateViewItemRelay.asDriver() } @@ -104,11 +102,9 @@ extension CoinMajorHoldersViewModel { func onTapRetry() { service.refresh() } - } extension CoinMajorHoldersViewModel { - struct ViewItem { let order: String let percent: String? @@ -125,5 +121,4 @@ extension CoinMajorHoldersViewModel { let viewItems: [ViewItem] let holdersUrl: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMarkets/CoinMarketsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMarkets/CoinMarketsViewModel.swift index 1d1eddde4b..61918eb11c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMarkets/CoinMarketsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMarkets/CoinMarketsViewModel.swift @@ -76,7 +76,7 @@ class CoinMarketsViewModel: ObservableObject { case .all: filteredTickers = tickers case .verified: - filteredTickers = tickers.filter { $0.verified } + filteredTickers = tickers.filter(\.verified) } let sortedTickers = filteredTickers.sorted { $0.volume > $1.volume } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewService.swift index 6f300b473d..0f6493585d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewService.swift @@ -43,7 +43,7 @@ class CoinOverviewService { } } - let walletTokens = walletManager.activeWallets.map { $0.token } + let walletTokens = walletManager.activeWallets.map(\.token) let tokenItems = tokens .sorted { lhsToken, rhsToken in @@ -59,7 +59,7 @@ class CoinOverviewService { .map { token in let state: TokenItemState - if let account = account, !account.watchAccount, account.type.supports(token: token) { + if let account, !account.watchAccount, account.type.supports(token: token) { if walletTokens.contains(token) { state = .alreadyAdded } else { @@ -79,7 +79,7 @@ class CoinOverviewService { } private var guideUrl: URL? { - guard let guideFileUrl = guideFileUrl else { + guard let guideFileUrl else { return nil } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewView.swift index 8d9733777b..7daa4e35c7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewView.swift @@ -122,7 +122,7 @@ struct CoinOverviewView: View { } private func format(value: Decimal?, coinCode: String) -> String? { - guard let value = value, !value.isZero else { + guard let value, !value.isZero else { return nil } @@ -130,7 +130,7 @@ struct CoinOverviewView: View { } private func format(value: Decimal?, currency: Currency) -> String? { - guard let value = value, !value.isZero else { + guard let value, !value.isZero else { return nil } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewController.swift index 05bea222cf..7674e4122b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewController.swift @@ -293,7 +293,7 @@ extension CoinOverviewViewController { private func linksSection(guideUrl: URL?, links: [CoinOverviewViewModel.LinkViewItem]) -> SectionProtocol { var guideRows = [RowProtocol]() - if let guideUrl = guideUrl { + if let guideUrl { let isLast = links.isEmpty let guideRow = linkRow( @@ -483,7 +483,7 @@ extension CoinOverviewViewController { .badge { (component: BadgeComponent) in component.badgeView.set(style: .small) - if let badge = badge { + if let badge { component.badgeView.text = badge component.isHidden = false } else { @@ -552,7 +552,7 @@ extension CoinOverviewViewController: SectionsDataSource { public func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let viewItem = viewItem { + if let viewItem { sections.append(coinInfoSection(viewItem: viewItem.coinViewItem)) sections.append(chartSection) sections.append( diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewItemFactory.swift index af7013e8dc..8ec5f04f2d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewItemFactory.swift @@ -3,7 +3,7 @@ import MarketKit class CoinOverviewViewItemFactory { private func roundedFormat(coinCode: String, value: Decimal?) -> String? { - guard let value = value, !value.isZero, let formattedValue = ValueFormatter.instance.formatShort(value: value, decimalCount: 0, symbol: coinCode) else { + guard let value, !value.isZero, let formattedValue = ValueFormatter.instance.formatShort(value: value, decimalCount: 0, symbol: coinCode) else { return nil } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewModelNew.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewModelNew.swift index 9ff4e514e2..a764a928ce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewModelNew.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinOverview/CoinOverviewViewModelNew.swift @@ -42,9 +42,7 @@ class CoinOverviewViewModelNew: ObservableObject { } } - let walletTokens = walletManager.activeWallets.map { - $0.token - } + let walletTokens = walletManager.activeWallets.map(\.token) let tokenItems = tokens .sorted { lhsToken, rhsToken in @@ -60,7 +58,7 @@ class CoinOverviewViewModelNew: ObservableObject { .map { token in let state: TokenItemState - if let account = account, !account.watchAccount, account.type.supports(token: token) { + if let account, !account.watchAccount, account.type.supports(token: token) { if walletTokens.contains(token) { state = .alreadyAdded } else { @@ -88,7 +86,7 @@ class CoinOverviewViewModelNew: ObservableObject { } private var guideUrl: URL? { - guard let guideFileUrl = guideFileUrl else { + guard let guideFileUrl else { return nil } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageService.swift index fe61d34124..c64ae2b6bc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class CoinPageService { let fullCoin: FullCoin @@ -29,11 +29,9 @@ class CoinPageService { private func syncFavorite() { favorite = favoritesManager.isFavorite(coinUid: fullCoin.coin.uid) } - } extension CoinPageService { - var favoriteObservable: Observable { favoriteRelay.asObservable() } @@ -45,5 +43,4 @@ extension CoinPageService { favoritesManager.add(coinUid: fullCoin.coin.uid) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageView.swift index b92a8b395e..94908771b8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageView.swift @@ -15,7 +15,7 @@ struct CoinPageView: View { ThemeView { VStack(spacing: 0) { TabHeaderView( - tabs: Tab.allCases.map { $0.title }, + tabs: Tab.allCases.map(\.title), currentTabIndex: $currentTabIndex ) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewController.swift index 4761e47d3f..d1c096fd33 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewController.swift @@ -1,11 +1,11 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import SnapKit -import RxSwift -import RxCocoa import HUD -import ComponentKit +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class CoinPageViewController: ThemeViewController { private let viewModel: CoinPageViewModel @@ -31,7 +31,8 @@ class CoinPageViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -115,15 +116,14 @@ class CoinPageViewController: ThemeViewController { var items = [UIBarButtonItem]() let favoriteItem = UIBarButtonItem( - image: favorite ? UIImage(named: "filled_star_24") : UIImage(named: "star_24"), - style: .plain, - target: self, - action: #selector(onTapFavorite) + image: favorite ? UIImage(named: "filled_star_24") : UIImage(named: "star_24"), + style: .plain, + target: self, + action: #selector(onTapFavorite) ) favoriteItem.tintColor = favorite ? .themeJacob : .themeGray items.append(favoriteItem) navigationItem.rightBarButtonItems = items } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewModel.swift index 1a150cf9aa..8a696603bf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewModel.swift @@ -1,8 +1,8 @@ +import ComponentKit import Foundation -import RxSwift -import RxRelay import RxCocoa -import ComponentKit +import RxRelay +import RxSwift class CoinPageViewModel { private let service: CoinPageService @@ -21,11 +21,9 @@ class CoinPageViewModel { self?.hudRelay.accept(favorite ? .addedToWatchlist : .removedFromWatchlist) } } - } extension CoinPageViewModel { - var favoriteDriver: Driver { favoriteRelay.asDriver() } @@ -41,5 +39,4 @@ extension CoinPageViewModel { func onTapFavorite() { service.toggleFavorite() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Cells/TweetCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Cells/TweetCell.swift index 61248a3373..1b8db0ea5b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Cells/TweetCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Cells/TweetCell.swift @@ -1,5 +1,5 @@ -import UIKit import ComponentKit +import UIKit class TweetCell: BaseSelectableThemeCell { private static let bodyFont: UIFont = .subhead2 @@ -92,12 +92,12 @@ class TweetCell: BaseSelectableThemeCell { let attributedString = NSMutableAttributedString(string: viewItem.text, attributes: [ .foregroundColor: UIColor.themeLeah, - .font: Self.bodyFont + .font: Self.bodyFont, ]) - + for entity in TwitterText.entities(in: viewItem.text) { switch entity.type { - case .url, .hashtag, .screenName, .listname: attributedString.addAttribute(.foregroundColor, value: UIColor.themeLaguna, range: entity.range) + case .url, .hashtag, .screenName, .listname: attributedString.addAttribute(.foregroundColor, value: UIColor.themeLaguna, range: entity.range) default: () } } @@ -136,5 +136,4 @@ class TweetCell: BaseSelectableThemeCell { return height + .margin12 + Self.dateFont.lineHeight + .margin16 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsModule.swift index 2153d6ebec..470db74d9f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsModule.swift @@ -1,25 +1,23 @@ import MarketKit struct CoinTweetsModule { - static func viewController(fullCoin: FullCoin) -> CoinTweetsViewController { let tweetsProvider = TweetsProvider( - networkManager: App.shared.networkManager, - bearerToken: AppConfig.twitterBearerToken + networkManager: App.shared.networkManager, + bearerToken: AppConfig.twitterBearerToken ) let service = CoinTweetsService( - coinUid: fullCoin.coin.uid, - twitterProvider: tweetsProvider, - marketKit: App.shared.marketKit + coinUid: fullCoin.coin.uid, + twitterProvider: tweetsProvider, + marketKit: App.shared.marketKit ) let viewModel = CoinTweetsViewModel(service: service) return CoinTweetsViewController( - viewModel: viewModel, - urlManager: UrlManager(inApp: true) + viewModel: viewModel, + urlManager: UrlManager(inApp: true) ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsService.swift index 9e01284915..48d487020b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift class CoinTweetsService { private var tasks = Set() @@ -9,7 +9,7 @@ class CoinTweetsService { private let marketKit: MarketKit.Kit private let coinUid: String - private var user: TwitterUser? = nil + private var user: TwitterUser? private let stateRelay = PublishRelay>() private(set) var state: DataStatus<[Tweet]> = .loading { @@ -17,7 +17,7 @@ class CoinTweetsService { stateRelay.accept(state) } } - + init(coinUid: String, twitterProvider: TweetsProvider, marketKit: MarketKit.Kit) { self.coinUid = coinUid self.twitterProvider = twitterProvider @@ -27,11 +27,9 @@ class CoinTweetsService { private func handle(tweets: [Tweet]) { state = .completed(tweets) } - } extension CoinTweetsService { - var stateObservable: Observable> { stateRelay.asObservable() } @@ -73,13 +71,10 @@ extension CoinTweetsService { } }.store(in: &tasks) } - } extension CoinTweetsService { - enum LoadError: Error { case tweeterUserNotFound } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewController.swift index 809b9b0a2f..6a0c885244 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import RxSwift -import ThemeKit -import SectionsTableView import ComponentKit import HUD +import RxSwift +import SectionsTableView +import ThemeKit +import UIKit class CoinTweetsViewController: ThemeViewController { private let viewModel: CoinTweetsViewModel @@ -27,7 +27,8 @@ class CoinTweetsViewController: ThemeViewController { super.init() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -84,7 +85,7 @@ class CoinTweetsViewController: ThemeViewController { self?.spinner.isHidden = !loading } subscribe(disposeBag, viewModel.infoDriver) { [weak self] info in - if let info = info { + if let info { self?.infoView.text = info self?.infoView.isHidden = false } else { @@ -154,56 +155,54 @@ class CoinTweetsViewController: ThemeViewController { let webUrl = "https://twitter.com/\(username)" urlManager.open(url: webUrl, from: parentNavigationController) } - } extension CoinTweetsViewController: SectionsDataSource { - private func row(viewItem: CoinTweetsViewModel.ViewItem) -> RowProtocol { Row( - id: viewItem.id, - autoDeselect: true, - dynamicHeight: { containerWidth in TweetCell.height(viewItem: viewItem, containerWidth: containerWidth) }, - bind: { cell, _ in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - cell.bind(viewItem: viewItem) - }, - action: { [weak self] _ in - self?.open(username: viewItem.username, tweetId: viewItem.id) - } + id: viewItem.id, + autoDeselect: true, + dynamicHeight: { containerWidth in TweetCell.height(viewItem: viewItem, containerWidth: containerWidth) }, + bind: { cell, _ in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + cell.bind(viewItem: viewItem) + }, + action: { [weak self] _ in + self?.open(username: viewItem.username, tweetId: viewItem.id) + } ) } private func buttonSection() -> SectionProtocol { Section( - id: "button_section", - headerState: .margin(height: .margin16), - footerState: .margin(height: .margin16), - rows: [ - Row( - id: "see-on-twitter", - height: SecondaryButtonCell.height(style: .default), - bind: { [weak self] cell, _ in - cell.set(style: .default) - cell.title = "coin_tweets.see_on_twitter".localized - cell.onTap = { - self?.onTapSeeOnTwitter() - } - } - ) - ] + id: "button_section", + headerState: .margin(height: .margin16), + footerState: .margin(height: .margin16), + rows: [ + Row( + id: "see-on-twitter", + height: SecondaryButtonCell.height(style: .default), + bind: { [weak self] cell, _ in + cell.set(style: .default) + cell.title = "coin_tweets.see_on_twitter".localized + cell.onTap = { + self?.onTapSeeOnTwitter() + } + } + ), + ] ) } func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let viewItems = viewItems { + if let viewItems { for (index, viewItem) in viewItems.enumerated() { let section = Section( - id: "tweet_\(index)", - headerState: .margin(height: .margin12), - rows: [row(viewItem: viewItem)] + id: "tweet_\(index)", + headerState: .margin(height: .margin12), + rows: [row(viewItem: viewItem)] ) sections.append(section) @@ -214,5 +213,4 @@ extension CoinTweetsViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewModel.swift index 9e00abc362..e0618794e2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/CoinTweetsViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinTweetsViewModel { private let service: CoinTweetsService @@ -27,12 +27,12 @@ class CoinTweetsViewModel { loadingRelay.accept(true) infoRelay.accept(nil) syncErrorRelay.accept(false) - case .completed(let tweets): + case let .completed(tweets): viewItemsRelay.accept(tweets.map { viewItem(tweet: $0) }) loadingRelay.accept(false) infoRelay.accept(tweets.isEmpty ? "coin_tweets.no_tweets_yet".localized : nil) syncErrorRelay.accept(false) - case .failed(let error): + case let .failed(error): viewItemsRelay.accept(nil) loadingRelay.accept(false) @@ -48,27 +48,25 @@ class CoinTweetsViewModel { private func viewItem(tweet: Tweet) -> ViewItem { ViewItem( - id: tweet.id, - title: tweet.user.name, - subTitle: "@\(tweet.user.username)", - username: tweet.user.username, - titleImageUrl: tweet.user.profileImageUrl, - text: tweet.text, - attachment: tweet.attachments.first, - date: DateHelper.instance.formatFullTime(from: tweet.date), - referencedTweet: tweet.referencedTweet.map { referencedTweet in - ReferencedTweet( - title: "coin_tweets.reference_type.\(referencedTweet.referenceType.rawValue)".localized(referencedTweet.tweet.user.username), - text: referencedTweet.tweet.text - ) - } + id: tweet.id, + title: tweet.user.name, + subTitle: "@\(tweet.user.username)", + username: tweet.user.username, + titleImageUrl: tweet.user.profileImageUrl, + text: tweet.text, + attachment: tweet.attachments.first, + date: DateHelper.instance.formatFullTime(from: tweet.date), + referencedTweet: tweet.referencedTweet.map { referencedTweet in + ReferencedTweet( + title: "coin_tweets.reference_type.\(referencedTweet.referenceType.rawValue)".localized(referencedTweet.tweet.user.username), + text: referencedTweet.tweet.text + ) + } ) } - } extension CoinTweetsViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -96,11 +94,9 @@ extension CoinTweetsViewModel { func viewDidLoad() { service.fetch() } - } extension CoinTweetsViewModel { - struct ViewItem { let id: String let title: String @@ -117,5 +113,4 @@ extension CoinTweetsViewModel { let title: String let text: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/Tweet.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/Tweet.swift index b10df737bd..313743a1fe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/Tweet.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/Tweet.swift @@ -8,7 +8,7 @@ class Tweet { let date: Date let attachments: [Attachment] let referencedTweet: (referenceType: ReferenceType, tweet: Tweet)? - + init(id: String, user: TwitterUser, text: String, date: Date, attachments: [Attachment], referencedTweet: (referenceType: ReferenceType, tweet: Tweet)?) { self.id = id self.user = user @@ -27,5 +27,4 @@ class Tweet { enum ReferenceType: String { case quoted, retweeted, replied } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TweetsPageResponse.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TweetsPageResponse.swift index 878c147256..6410108a2e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TweetsPageResponse.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TweetsPageResponse.swift @@ -40,14 +40,15 @@ class TweetsPageResponse: ImmutableMappable { var referencedTweet: (referenceType: Tweet.ReferenceType, tweet: Tweet)? = nil if let tweetReference = rawTweet.referencedTweets.first, let rawReferencedTweet = referencedTweets.first(where: { tweet in tweet.id == tweetReference.id }), - let referencedTweetAuthor = users.first(where: { user in user.id == rawReferencedTweet.authorId }) { + let referencedTweetAuthor = users.first(where: { user in user.id == rawReferencedTweet.authorId }) + { let tweet = Tweet( - id: rawReferencedTweet.id, - user: referencedTweetAuthor, - text: rawReferencedTweet.text, - date: rawReferencedTweet.date, - attachments: [], - referencedTweet: nil + id: rawReferencedTweet.id, + user: referencedTweetAuthor, + text: rawReferencedTweet.text, + date: rawReferencedTweet.date, + attachments: [], + referencedTweet: nil ) switch tweetReference.type { @@ -59,20 +60,18 @@ class TweetsPageResponse: ImmutableMappable { } return Tweet( - id: rawTweet.id, - user: user, - text: rawTweet.text, - date: rawTweet.date, - attachments: attachments, - referencedTweet: referencedTweet + id: rawTweet.id, + user: user, + text: rawTweet.text, + date: rawTweet.date, + attachments: attachments, + referencedTweet: referencedTweet ) } } - } extension TweetsPageResponse { - struct RawTweet: ImmutableMappable { let id: String let date: Date @@ -103,7 +102,7 @@ extension TweetsPageResponse { self.mentions = mentions self.hashTags = hashTags } - + init(map: Map) throws { urls = (try? map.value("urls")) ?? [] mentions = (try? map.value("mentions")) ?? [] @@ -194,11 +193,9 @@ extension TweetsPageResponse { id = try map.value("id") } } - } extension TweetsPageResponse { - static var utcDateFormatter: DateFormatter { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" @@ -208,11 +205,10 @@ extension TweetsPageResponse { } static let utcDateTransform: TransformOf = TransformOf(fromJSON: { string -> Date? in - guard let string = string else { return nil } + guard let string else { return nil } return utcDateFormatter.date(from: string) }, toJSON: { (value: Date?) in - guard let value = value else { return nil } + guard let value else { return nil } return utcDateFormatter.string(from: value) }) - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TwitterUsersResponse.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TwitterUsersResponse.swift index 4df1c2df96..aba4942b05 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TwitterUsersResponse.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Models/TwitterUsersResponse.swift @@ -6,7 +6,6 @@ struct TwitterUsersResponse: ImmutableMappable { init(map: Map) throws { users = try map.value("data") } - } struct TwitterUser: ImmutableMappable { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TweetsProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TweetsProvider.swift index d3c8abf855..5b95747961 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TweetsProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TweetsProvider.swift @@ -1,7 +1,7 @@ +import Alamofire import Foundation import HsToolKit import ObjectMapper -import Alamofire class TweetsProvider { typealias TweetsPage = (tweets: [Tweet], nextToken: String?) @@ -18,7 +18,7 @@ class TweetsProvider { func userRequest(username: String) async throws -> TwitterUser? { let parameters: Parameters = [ "usernames": username, - "user.fields": "profile_image_url" + "user.fields": "profile_image_url", ] let headers = bearerToken.map { HTTPHeaders([HTTPHeader.authorization(bearerToken: $0)]) } @@ -33,14 +33,14 @@ class TweetsProvider { "expansions": "attachments.poll_ids,attachments.media_keys,referenced_tweets.id,referenced_tweets.id.author_id", "media.fields": "media_key,preview_image_url,type,url", "tweet.fields": "id,author_id,created_at,attachments", - "user.fields": "profile_image_url" + "user.fields": "profile_image_url", ] if let token = paginationToken { - parameters["next_token"] = token + parameters["next_token"] = token } - if let sinceId = sinceId { + if let sinceId { parameters["since_id"] = sinceId } @@ -49,5 +49,4 @@ class TweetsProvider { let tweetsResponse: TweetsPageResponse = try await networkManager.fetch(url: "\(baseUrl)/users/\(user.id)/tweets", method: .get, parameters: parameters, headers: headers) return (tweets: tweetsResponse.tweets(user: user), nextToken: tweetsResponse.nextToken) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TwitterText/TwitterText.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TwitterText/TwitterText.swift index cd9c5f69ed..e4eb8f727f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TwitterText/TwitterText.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/TwitterText/TwitterText.swift @@ -1,6 +1,6 @@ +import CoreFoundation import Foundation import UnicodeURL -import CoreFoundation class TwitterText { static let maxURLLength = 4096 @@ -21,13 +21,13 @@ class TwitterText { } var results: [Entity] = [] - let urls = self.urls(in: text) + let urls = urls(in: text) results.append(contentsOf: urls) - let hashtags = self.hashtags(in: text, with: urls) + let hashtags = hashtags(in: text, with: urls) results.append(contentsOf: hashtags) - let symbols = self.symbols(in: text, with: urls) + let symbols = symbols(in: text, with: urls) results.append(contentsOf: symbols) var addingItems: [Entity] = [] @@ -69,7 +69,7 @@ class TwitterText { break } - guard let urlResult = self.validURLRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) else { + guard let urlResult = validURLRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) else { break } @@ -84,17 +84,17 @@ class TwitterText { let nsProtocolRange = urlResult.range(at: ValidURLGroup.urlProtocol.rawValue) let nsDomainRange = urlResult.range(at: ValidURLGroup.domain.rawValue) - var urlProtocol: String? = nil + var urlProtocol: String? if nsProtocolRange.location != NSNotFound, let protocolRange = Range(nsProtocolRange, in: text) { urlProtocol = String(text[protocolRange]) } if urlProtocol == nil || urlProtocol?.count == 0 { - var preceding: String? = nil + var preceding: String? if nsPrecedingRange.location != NSNotFound, let precedingRange = Range(nsPrecedingRange, in: text) { preceding = String(text[precedingRange]) } - if let set = preceding?.rangeOfCharacter(from: self.invalidURLWithoutProtocolPrecedingCharSet, options: [.backwards, .anchored]) { + if let set = preceding?.rangeOfCharacter(from: invalidURLWithoutProtocolPrecedingCharSet, options: [.backwards, .anchored]) { let suffixRange = NSRange(set, in: preceding!) if suffixRange.location != NSNotFound { continue @@ -102,12 +102,12 @@ class TwitterText { } } - var url: String? = nil + var url: String? if nsUrlRange.location != NSNotFound, let urlRange = Range(nsUrlRange, in: text) { url = String(text[urlRange]) } - var host: String? = nil + var host: String? if nsDomainRange.location != NSNotFound, let domainRange = Range(nsDomainRange, in: text) { host = String(text[domainRange]) } @@ -116,13 +116,13 @@ class TwitterText { var end = NSMaxRange(nsUrlRange) let tcoResult: NSTextCheckingResult? - if let url = url { - tcoResult = self.validTCOURLRegexp.firstMatch(in: url, options: [], range: NSMakeRange(0, url.utf16.count)) + if let url { + tcoResult = validTCOURLRegexp.firstMatch(in: url, options: [], range: NSMakeRange(0, url.utf16.count)) } else { tcoResult = nil } - if let tcoResult = tcoResult, tcoResult.numberOfRanges >= 2 { + if let tcoResult, tcoResult.numberOfRanges >= 2 { let nsTcoRange = tcoResult.range(at: 0) let nsTcoUrlSlugRange = tcoResult.range(at: 1) @@ -166,7 +166,7 @@ class TwitterText { urls = self.urls(in: text) } - return self.hashtags(in: text, with: urls) + return hashtags(in: text, with: urls) } static func hashtags(in text: String, with urlEntities: [Entity]) -> [Entity] { @@ -179,7 +179,7 @@ class TwitterText { var position = 0 while true { - let matchResult = self.validHashtagRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) + let matchResult = validHashtagRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) guard let result = matchResult, result.numberOfRanges > 1 else { break @@ -198,7 +198,7 @@ class TwitterText { if matchOk { let afterStart = NSMaxRange(hashtagRange) if afterStart < len { - let endMatchRange = self.endHashtagRegexp.rangeOfFirstMatch(in: text, options: [], range: NSMakeRange(afterStart, len - afterStart)) + let endMatchRange = endHashtagRegexp.rangeOfFirstMatch(in: text, options: [], range: NSMakeRange(afterStart, len - afterStart)) if endMatchRange.location != NSNotFound { matchOk = false } @@ -239,7 +239,7 @@ class TwitterText { var position = 0 while true { - let matchResult = self.validSymbolRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) + let matchResult = validSymbolRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) guard let result = matchResult, result.numberOfRanges >= 2 else { break @@ -271,7 +271,7 @@ class TwitterText { return [] } - let mentionsOrLists = self.mentionsOrLists(in: text) + let mentionsOrLists = mentionsOrLists(in: text) var results: [Entity] = [] for entity in mentionsOrLists { @@ -293,7 +293,7 @@ class TwitterText { var position = 0 while true { - let matchResult = self.validMentionOrListRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) + let matchResult = validMentionOrListRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds], range: NSMakeRange(position, len - position)) guard let result = matchResult, result.numberOfRanges >= 5 else { break @@ -302,7 +302,7 @@ class TwitterText { let allRange = result.range var end = NSMaxRange(allRange) - let endMentionRange = self.endMentionRegexp.rangeOfFirstMatch(in: text, options: [], range: NSMakeRange(end, len - end)) + let endMentionRange = endMentionRegexp.rangeOfFirstMatch(in: text, options: [], range: NSMakeRange(end, len - end)) if endMentionRange.location == NSNotFound { let atSignRange = result.range(at: 2) let screenNameRange = result.range(at: 3) @@ -331,7 +331,7 @@ class TwitterText { } let len = text.utf16.count - let matchResult = self.validReplyRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds, .anchored], range: NSMakeRange(0, len)) + let matchResult = validReplyRegexp.firstMatch(in: text, options: [.withoutAnchoringBounds, .anchored], range: NSMakeRange(0, len)) guard let result = matchResult, result.numberOfRanges >= 2 else { return nil @@ -339,7 +339,7 @@ class TwitterText { let replyRange = result.range(at: 1) let replyEnd = NSMaxRange(replyRange) - let endMentionRange = self.endMentionRegexp.rangeOfFirstMatch(in: text, options: [], range: NSMakeRange(replyEnd, len - replyEnd)) + let endMentionRange = endMentionRegexp.rangeOfFirstMatch(in: text, options: [], range: NSMakeRange(replyEnd, len - replyEnd)) if endMentionRange.location != NSNotFound { return nil @@ -357,7 +357,7 @@ class TwitterText { } static func tweetLength(text: String) -> Int { - return self.tweetLength(text: text, transformedURLLength: transformedURLLength) + tweetLength(text: text, transformedURLLength: transformedURLLength) } static func tweetLength(text: String, transformedURLLength: Int) -> Int { @@ -387,12 +387,12 @@ class TwitterText { var charCount = len + urlLengthOffset if len > 0 { - var buffer: [UniChar] = Array.init(repeating: UniChar(), count: len) + var buffer: [UniChar] = Array(repeating: UniChar(), count: len) let mutableString = NSMutableString(string: string) mutableString.getCharacters(&buffer, range: NSMakeRange(0, len)) - for index in 0.. Int { - self.remainingCharacterCount(text: text, transformedURLLength: transformedURLLength) + remainingCharacterCount(text: text, transformedURLLength: transformedURLLength) } static func remainingCharacterCount(text: String, transformedURLLength: Int) -> Int { - maxTweetLengthLegacy - self.tweetLength(text: text, transformedURLLength: transformedURLLength) + maxTweetLengthLegacy - tweetLength(text: text, transformedURLLength: transformedURLLength) } // MARK: - Private Methods - internal static let invalidCharacterRegexp = try! NSRegularExpression(pattern: Regexp.TWUInvalidCharactersPattern, options: .caseInsensitive) + static let invalidCharacterRegexp = try! NSRegularExpression(pattern: Regexp.TWUInvalidCharactersPattern, options: .caseInsensitive) private static let validGTLDRegexp = try! NSRegularExpression(pattern: Regexp.TWUValidGTLD, options: .caseInsensitive) @@ -438,12 +438,10 @@ class TwitterText { private static let endMentionRegexp = try! NSRegularExpression(pattern: Regexp.TWUEndMentionMatch, options: .caseInsensitive) - private static let invalidURLWithoutProtocolPrecedingCharSet: CharacterSet = { - CharacterSet.init(charactersIn: "-_./") - }() + private static let invalidURLWithoutProtocolPrecedingCharSet: CharacterSet = .init(charactersIn: "-_./") private static func isValidHostAndLength(urlLength: Int, urlProtocol: String?, host: String?) -> Bool { - guard var host = host else { + guard var host else { return false } var urlLength = urlLength @@ -456,11 +454,10 @@ class TwitterText { } else { hostUrl = URL(string: host) } - } catch { - } + } catch {} if hostUrl == nil { - hostUrl = URL.init(string: host) + hostUrl = URL(string: host) } guard let url = hostUrl else { @@ -551,9 +548,9 @@ class TwitterText { static let TWUIdeographicSpace = "\\u3000" static let TWUUnicodeSpaces = "\(TWUControlCharacters)\(TWUSpace)\(TWUControl85)" - + "\(TWUNoBreakSpace)\(TWUOghamBreakSpace)\(TWUMongolianVowelSeparator)" - + "\(TWUWhiteSpaces)\(TWULineSeparator)\(TWUParagraphSeparator)" - + "\(TWUNarrowNoBreakSpace)\(TWUMediumMathematicalSpace)\(TWUIdeographicSpace)" + + "\(TWUNoBreakSpace)\(TWUOghamBreakSpace)\(TWUMongolianVowelSeparator)" + + "\(TWUWhiteSpaces)\(TWULineSeparator)\(TWUParagraphSeparator)" + + "\(TWUNarrowNoBreakSpace)\(TWUMediumMathematicalSpace)\(TWUIdeographicSpace)" static let TWUUnicodeALM = "\\u061C" static let TWUUnicodeLRM = "\\u200E" @@ -569,8 +566,8 @@ class TwitterText { static let TWUUnicodePDI = "\\u2069" static let TWUUnicodeDirectionalCharacters = "\(TWUUnicodeALM)\(TWUUnicodeLRM)" - + "\(TWUUnicodeLRE)\(TWUUnicodeRLE)\(TWUUnicodePDF)\(TWUUnicodeLRO)" - + "\(TWUUnicodeRLO)\(TWUUnicodeLRI)\(TWUUnicodeRLI)\(TWUUnicodeFSI)\(TWUUnicodePDI)" + + "\(TWUUnicodeLRE)\(TWUUnicodeRLE)\(TWUUnicodePDF)\(TWUUnicodeLRO)" + + "\(TWUUnicodeRLO)\(TWUUnicodeLRI)\(TWUUnicodeRLI)\(TWUUnicodeFSI)\(TWUUnicodePDI)" static let TWUInvalidCharacters = "\\uFFFE\\uFEFF\\uFFFF" static let TWUInvalidCharactersPattern = "[\(TWUInvalidCharacters)]" @@ -597,7 +594,7 @@ class TwitterText { static let TWUSymbol = "[a-z]{1,6}(?:[._][a-z]{1,2})?" static let TWUValidSymbol = "(?:^|[\(TWUUnicodeSpaces)\(TWUUnicodeDirectionalCharacters)])" - + "(\\$\(TWUSymbol))(?=$|\\s|[\(TWUPunctuationChars)])" + + "(\\$\(TWUSymbol))(?=$|\\s|[\(TWUPunctuationChars)])" // MARK: - Mention and list name @@ -607,10 +604,10 @@ class TwitterText { static let TWUValidList = "\\A\(TWUAtSigns)[a-z0-9_]{1,20}/[a-z][a-z0-9_\\-]{0,24}\\z" static let TWUValidMentionOrList = "(\(TWUValidMentionPrecedingChars))" - + "(\(TWUAtSigns))([a-z0-9_]{1,20})(/[a-z][a-z0-9_\\-]{0,24})?" + + "(\(TWUAtSigns))([a-z0-9_]{1,20})(/[a-z][a-z0-9_\\-]{0,24})?" static let TWUValidReply = "\\A(?:[\(TWUUnicodeSpaces)" - + "\(TWUUnicodeDirectionalCharacters)])*\(TWUAtSigns)([a-z0-9_]{1,20})" + + "\(TWUUnicodeDirectionalCharacters)])*\(TWUAtSigns)([a-z0-9_]{1,20})" static let TWUEndMentionMatch = "\\A(?:\(TWUAtSigns)|[\(TWULatinAccents)]|://)" @@ -622,157 +619,156 @@ class TwitterText { /// for unencoded domains with unicode characters elsewhere. static let TWUValidURLCharacters = "[a-z0-9\(TWULatinAccents)]" static let TWUValidURLSubdomain = "(?>(?:\(TWUValidURLCharacters)" - + "[\(TWUValidURLCharacters)\\-_]{0,255})?\(TWUValidURLCharacters)\\.)" + + "[\(TWUValidURLCharacters)\\-_]{0,255})?\(TWUValidURLCharacters)\\.)" static let TWUValidURLDomain = "(?:(?:\(TWUValidURLCharacters)" - + "[\(TWUValidURLCharacters)\\-]{0,255})?\(TWUValidURLCharacters)\\.)" + + "[\(TWUValidURLCharacters)\\-]{0,255})?\(TWUValidURLCharacters)\\.)" /// Used to extract domains that contain unencoded unicode. static let TWUValidURLUnicodeCharacters = "[^\(TWUPunctuationChars)\\s\\p{Z}\\p{InGeneralPunctuation}]" static let TWUValidURLUnicodeDomain = "(?:(?:\(TWUValidURLUnicodeCharacters)" - + "[\(TWUValidURLUnicodeCharacters)\\-]{0,255})?\(TWUValidURLUnicodeCharacters)\\.)" + + "[\(TWUValidURLUnicodeCharacters)\\-]{0,255})?\(TWUValidURLUnicodeCharacters)\\.)" static let TWUValidPunycode = "(?:xn--[-0-9a-z]+)" static let TWUValidDomain = "(?:\(TWUValidURLSubdomain)*\(TWUValidURLDomain)" - + "(?:\(TWUValidGTLD)|\(TWUValidCCTLD)|\(TWUValidPunycode))" - + ")|(?:(?<=https?://)(?:(?:\(TWUValidURLDomain)\(TWUValidCCTLD))" - + "|(?:\(TWUValidURLUnicodeDomain){0,255}\(TWUValidURLUnicodeDomain)" - + "(?:\(TWUValidGTLD)|\(TWUValidCCTLD)))))|(?:" - + "\(TWUValidURLDomain)\(TWUValidCCTLD)(?=/))" + + "(?:\(TWUValidGTLD)|\(TWUValidCCTLD)|\(TWUValidPunycode))" + + ")|(?:(?<=https?://)(?:(?:\(TWUValidURLDomain)\(TWUValidCCTLD))" + + "|(?:\(TWUValidURLUnicodeDomain){0,255}\(TWUValidURLUnicodeDomain)" + + "(?:\(TWUValidGTLD)|\(TWUValidCCTLD)))))|(?:" + + "\(TWUValidURLDomain)\(TWUValidCCTLD)(?=/))" static let TWUValidPortNumber = "[0-9]++" static let TWUValidGeneralURLPathChars = "[a-z\\p{Cyrillic}0-9!\\*';:=+,.$/%#\\[\\]\\-\\u2013_~&|@\(TWULatinAccents)]" static let TWUValidURLBalancedParens = "\\((?:\(TWUValidGeneralURLPathChars)+" - + "|(?:\(TWUValidGeneralURLPathChars)*\\(\(TWUValidGeneralURLPathChars)+" - + "\\)\(TWUValidGeneralURLPathChars)*))\\)" + + "|(?:\(TWUValidGeneralURLPathChars)*\\(\(TWUValidGeneralURLPathChars)+" + + "\\)\(TWUValidGeneralURLPathChars)*))\\)" static let TWUValidURLPathEndingChars = "[a-z\\p{Cyrillic}0-9=_#/+\\-\(TWULatinAccents)]|(?:\(TWUValidURLBalancedParens))" static let TWUValidPath = "(?:(?:\(TWUValidGeneralURLPathChars)*" - + "(?:\(TWUValidURLBalancedParens)\(TWUValidGeneralURLPathChars)*)*" - + "\(TWUValidURLPathEndingChars))|(?:@\(TWUValidGeneralURLPathChars)+/))" + + "(?:\(TWUValidURLBalancedParens)\(TWUValidGeneralURLPathChars)*)*" + + "\(TWUValidURLPathEndingChars))|(?:@\(TWUValidGeneralURLPathChars)+/))" static let TWUValidURLQueryChars = "[a-z0-9!?*'\\(\\);:&=+$/%#\\[\\]\\-_\\.,~|@]" static let TWUValidURLQueryEndingChars = "[a-z0-9\\-_&=#/]" static let TWUValidURLPatternString = "((\(TWUValidURLPrecedingChars))" - + "((https?://)?(\(TWUValidDomain))(?::(\(TWUValidPortNumber)))?" - + "(/\(TWUValidPath)*+)?(\\?\(TWUValidURLQueryChars)*" - + "\(TWUValidURLQueryEndingChars))?))" + + "((https?://)?(\(TWUValidDomain))(?::(\(TWUValidPortNumber)))?" + + "(/\(TWUValidPath)*+)?(\\?\(TWUValidURLQueryChars)*" + + "\(TWUValidURLQueryEndingChars))?))" static let TWUValidGTLD = "(?:(?:" - + "삼성|닷컴|닷넷|香格里拉|餐厅|食品|飞利浦|電訊盈科|集团|通販|购物|谷歌|诺基亚|联通|网络|网站|网店|网址|组织机构|移动|珠宝|点看|游戏|淡马锡|机构|書籍|时尚|新闻|政府|政务|" - + "招聘|手表|手机|我爱你|慈善|微博|广东|工行|家電|娱乐|天主教|大拿|大众汽车|在线|嘉里大酒店|嘉里|商标|商店|商城|公益|公司|八卦|健康|信息|佛山|企业|中文网|中信|世界|ポイント|" - + "ファッション|セール|ストア|コム|グーグル|クラウド|みんな|คอม|संगठन|नेट|कॉम|همراه|موقع|موبايلي|كوم|كاثوليك|عرب|شبكة|بيتك|بازار|" - + "العليان|ارامكو|اتصالات|ابوظبي|קום|сайт|рус|орг|онлайн|москва|ком|католик|дети|zuerich|zone|zippo|zip|" - + "zero|zara|zappos|yun|youtube|you|yokohama|yoga|yodobashi|yandex|yamaxun|yahoo|yachts|xyz|xxx|xperia|" - + "xin|xihuan|xfinity|xerox|xbox|wtf|wtc|wow|world|works|work|woodside|wolterskluwer|wme|winners|wine|" - + "windows|win|williamhill|wiki|wien|whoswho|weir|weibo|wedding|wed|website|weber|webcam|weatherchannel|" - + "weather|watches|watch|warman|wanggou|wang|walter|walmart|wales|vuelos|voyage|voto|voting|vote|volvo|" - + "volkswagen|vodka|vlaanderen|vivo|viva|vistaprint|vista|vision|visa|virgin|vip|vin|villas|viking|vig|" - + "video|viajes|vet|versicherung|vermögensberatung|vermögensberater|verisign|ventures|vegas|vanguard|" - + "vana|vacations|ups|uol|uno|university|unicom|uconnect|ubs|ubank|tvs|tushu|tunes|tui|tube|trv|trust|" - + "travelersinsurance|travelers|travelchannel|travel|training|trading|trade|toys|toyota|town|tours|" - + "total|toshiba|toray|top|tools|tokyo|today|tmall|tkmaxx|tjx|tjmaxx|tirol|tires|tips|tiffany|tienda|" - + "tickets|tiaa|theatre|theater|thd|teva|tennis|temasek|telefonica|telecity|tel|technology|tech|team|" - + "tdk|tci|taxi|tax|tattoo|tatar|tatamotors|target|taobao|talk|taipei|tab|systems|symantec|sydney|swiss|" - + "swiftcover|swatch|suzuki|surgery|surf|support|supply|supplies|sucks|style|study|studio|stream|store|" - + "storage|stockholm|stcgroup|stc|statoil|statefarm|statebank|starhub|star|staples|stada|srt|srl|" - + "spreadbetting|spot|sport|spiegel|space|soy|sony|song|solutions|solar|sohu|software|softbank|social|" - + "soccer|sncf|smile|smart|sling|skype|sky|skin|ski|site|singles|sina|silk|shriram|showtime|show|shouji|" - + "shopping|shop|shoes|shiksha|shia|shell|shaw|sharp|shangrila|sfr|sexy|sex|sew|seven|ses|services|" - + "sener|select|seek|security|secure|seat|search|scot|scor|scjohnson|science|schwarz|schule|school|" - + "scholarships|schmidt|schaeffler|scb|sca|sbs|sbi|saxo|save|sas|sarl|sapo|sap|sanofi|sandvikcoromant|" - + "sandvik|samsung|samsclub|salon|sale|sakura|safety|safe|saarland|ryukyu|rwe|run|ruhr|rugby|rsvp|room|" - + "rogers|rodeo|rocks|rocher|rmit|rip|rio|ril|rightathome|ricoh|richardli|rich|rexroth|reviews|review|" - + "restaurant|rest|republican|report|repair|rentals|rent|ren|reliance|reit|reisen|reise|rehab|" - + "redumbrella|redstone|red|recipes|realty|realtor|realestate|read|raid|radio|racing|qvc|quest|quebec|" - + "qpon|pwc|pub|prudential|pru|protection|property|properties|promo|progressive|prof|productions|prod|" - + "pro|prime|press|praxi|pramerica|post|porn|politie|poker|pohl|pnc|plus|plumbing|playstation|play|" - + "place|pizza|pioneer|pink|ping|pin|pid|pictures|pictet|pics|piaget|physio|photos|photography|photo|" - + "phone|philips|phd|pharmacy|pfizer|pet|pccw|pay|passagens|party|parts|partners|pars|paris|panerai|" - + "panasonic|pamperedchef|page|ovh|ott|otsuka|osaka|origins|orientexpress|organic|org|orange|oracle|" - + "open|ooo|onyourside|online|onl|ong|one|omega|ollo|oldnavy|olayangroup|olayan|okinawa|office|off|" - + "observer|obi|nyc|ntt|nrw|nra|nowtv|nowruz|now|norton|northwesternmutual|nokia|nissay|nissan|ninja|" - + "nikon|nike|nico|nhk|ngo|nfl|nexus|nextdirect|next|news|newholland|new|neustar|network|netflix|" - + "netbank|net|nec|nba|navy|natura|nationwide|name|nagoya|nadex|nab|mutuelle|mutual|museum|mtr|mtpc|mtn|" - + "msd|movistar|movie|mov|motorcycles|moto|moscow|mortgage|mormon|mopar|montblanc|monster|money|monash|" - + "mom|moi|moe|moda|mobily|mobile|mobi|mma|mls|mlb|mitsubishi|mit|mint|mini|mil|microsoft|miami|metlife|" - + "merckmsd|meo|menu|men|memorial|meme|melbourne|meet|media|med|mckinsey|mcdonalds|mcd|mba|mattel|" - + "maserati|marshalls|marriott|markets|marketing|market|map|mango|management|man|makeup|maison|maif|" - + "madrid|macys|luxury|luxe|lupin|lundbeck|ltda|ltd|lplfinancial|lpl|love|lotto|lotte|london|lol|loft|" - + "locus|locker|loans|loan|llp|llc|lixil|living|live|lipsy|link|linde|lincoln|limo|limited|lilly|like|" - + "lighting|lifestyle|lifeinsurance|life|lidl|liaison|lgbt|lexus|lego|legal|lefrak|leclerc|lease|lds|" - + "lawyer|law|latrobe|latino|lat|lasalle|lanxess|landrover|land|lancome|lancia|lancaster|lamer|" - + "lamborghini|ladbrokes|lacaixa|kyoto|kuokgroup|kred|krd|kpn|kpmg|kosher|komatsu|koeln|kiwi|kitchen|" - + "kindle|kinder|kim|kia|kfh|kerryproperties|kerrylogistics|kerryhotels|kddi|kaufen|juniper|juegos|jprs|" - + "jpmorgan|joy|jot|joburg|jobs|jnj|jmp|jll|jlc|jio|jewelry|jetzt|jeep|jcp|jcb|java|jaguar|iwc|iveco|" - + "itv|itau|istanbul|ist|ismaili|iselect|irish|ipiranga|investments|intuit|international|intel|int|" - + "insure|insurance|institute|ink|ing|info|infiniti|industries|inc|immobilien|immo|imdb|imamat|ikano|" - + "iinet|ifm|ieee|icu|ice|icbc|ibm|hyundai|hyatt|hughes|htc|hsbc|how|house|hotmail|hotels|hoteles|hot|" - + "hosting|host|hospital|horse|honeywell|honda|homesense|homes|homegoods|homedepot|holiday|holdings|" - + "hockey|hkt|hiv|hitachi|hisamitsu|hiphop|hgtv|hermes|here|helsinki|help|healthcare|health|hdfcbank|" - + "hdfc|hbo|haus|hangout|hamburg|hair|guru|guitars|guide|guge|gucci|guardian|group|grocery|gripe|green|" - + "gratis|graphics|grainger|gov|got|gop|google|goog|goodyear|goodhands|goo|golf|goldpoint|gold|godaddy|" - + "gmx|gmo|gmbh|gmail|globo|global|gle|glass|glade|giving|gives|gifts|gift|ggee|george|genting|gent|gea|" - + "gdn|gbiz|gay|garden|gap|games|game|gallup|gallo|gallery|gal|fyi|futbol|furniture|fund|fun|fujixerox|" - + "fujitsu|ftr|frontier|frontdoor|frogans|frl|fresenius|free|fox|foundation|forum|forsale|forex|ford|" - + "football|foodnetwork|food|foo|fly|flsmidth|flowers|florist|flir|flights|flickr|fitness|fit|fishing|" - + "fish|firmdale|firestone|fire|financial|finance|final|film|fido|fidelity|fiat|ferrero|ferrari|" - + "feedback|fedex|fast|fashion|farmers|farm|fans|fan|family|faith|fairwinds|fail|fage|extraspace|" - + "express|exposed|expert|exchange|everbank|events|eus|eurovision|etisalat|esurance|estate|esq|erni|" - + "ericsson|equipment|epson|epost|enterprises|engineering|engineer|energy|emerck|email|education|edu|" - + "edeka|eco|eat|earth|dvr|dvag|durban|dupont|duns|dunlop|duck|dubai|dtv|drive|download|dot|doosan|" - + "domains|doha|dog|dodge|doctor|docs|dnp|diy|dish|discover|discount|directory|direct|digital|diet|" - + "diamonds|dhl|dev|design|desi|dentist|dental|democrat|delta|deloitte|dell|delivery|degree|deals|" - + "dealer|deal|dds|dclk|day|datsun|dating|date|data|dance|dad|dabur|cyou|cymru|cuisinella|csc|cruises|" - + "cruise|crs|crown|cricket|creditunion|creditcard|credit|cpa|courses|coupons|coupon|country|corsica|" - + "coop|cool|cookingchannel|cooking|contractors|contact|consulting|construction|condos|comsec|computer|" - + "compare|company|community|commbank|comcast|com|cologne|college|coffee|codes|coach|clubmed|club|cloud|" - + "clothing|clinique|clinic|click|cleaning|claims|cityeats|city|citic|citi|citadel|cisco|circle|" - + "cipriani|church|chrysler|chrome|christmas|chloe|chintai|cheap|chat|chase|charity|channel|chanel|cfd|" - + "cfa|cern|ceo|center|ceb|cbs|cbre|cbn|cba|catholic|catering|cat|casino|cash|caseih|case|casa|cartier|" - + "cars|careers|career|care|cards|caravan|car|capitalone|capital|capetown|canon|cancerresearch|camp|" - + "camera|cam|calvinklein|call|cal|cafe|cab|bzh|buzz|buy|business|builders|build|bugatti|budapest|" - + "brussels|brother|broker|broadway|bridgestone|bradesco|box|boutique|bot|boston|bostik|bosch|boots|" - + "booking|book|boo|bond|bom|bofa|boehringer|boats|bnpparibas|bnl|bmw|bms|blue|bloomberg|blog|" - + "blockbuster|blanco|blackfriday|black|biz|bio|bingo|bing|bike|bid|bible|bharti|bet|bestbuy|best|" - + "berlin|bentley|beer|beauty|beats|bcn|bcg|bbva|bbt|bbc|bayern|bauhaus|basketball|baseball|bargains|" - + "barefoot|barclays|barclaycard|barcelona|bar|bank|band|bananarepublic|banamex|baidu|baby|azure|axa|" - + "aws|avianca|autos|auto|author|auspost|audio|audible|audi|auction|attorney|athleta|associates|asia|" - + "asda|arte|art|arpa|army|archi|aramco|arab|aquarelle|apple|app|apartments|aol|anz|anquan|android|" - + "analytics|amsterdam|amica|amfam|amex|americanfamily|americanexpress|alstom|alsace|ally|allstate|" - + "allfinanz|alipay|alibaba|alfaromeo|akdn|airtel|airforce|airbus|aigo|aig|agency|agakhan|africa|afl|" - + "afamilycompany|aetna|aero|aeg|adult|ads|adac|actor|active|aco|accountants|accountant|accenture|" - + "academy|abudhabi|abogado|able|abc|abbvie|abbott|abb|abarth|aarp|aaa|onion" - + ")(?=[^a-z0-9@+-]|$))" + + "삼성|닷컴|닷넷|香格里拉|餐厅|食品|飞利浦|電訊盈科|集团|通販|购物|谷歌|诺基亚|联通|网络|网站|网店|网址|组织机构|移动|珠宝|点看|游戏|淡马锡|机构|書籍|时尚|新闻|政府|政务|" + + "招聘|手表|手机|我爱你|慈善|微博|广东|工行|家電|娱乐|天主教|大拿|大众汽车|在线|嘉里大酒店|嘉里|商标|商店|商城|公益|公司|八卦|健康|信息|佛山|企业|中文网|中信|世界|ポイント|" + + "ファッション|セール|ストア|コム|グーグル|クラウド|みんな|คอม|संगठन|नेट|कॉम|همراه|موقع|موبايلي|كوم|كاثوليك|عرب|شبكة|بيتك|بازار|" + + "العليان|ارامكو|اتصالات|ابوظبي|קום|сайт|рус|орг|онлайн|москва|ком|католик|дети|zuerich|zone|zippo|zip|" + + "zero|zara|zappos|yun|youtube|you|yokohama|yoga|yodobashi|yandex|yamaxun|yahoo|yachts|xyz|xxx|xperia|" + + "xin|xihuan|xfinity|xerox|xbox|wtf|wtc|wow|world|works|work|woodside|wolterskluwer|wme|winners|wine|" + + "windows|win|williamhill|wiki|wien|whoswho|weir|weibo|wedding|wed|website|weber|webcam|weatherchannel|" + + "weather|watches|watch|warman|wanggou|wang|walter|walmart|wales|vuelos|voyage|voto|voting|vote|volvo|" + + "volkswagen|vodka|vlaanderen|vivo|viva|vistaprint|vista|vision|visa|virgin|vip|vin|villas|viking|vig|" + + "video|viajes|vet|versicherung|vermögensberatung|vermögensberater|verisign|ventures|vegas|vanguard|" + + "vana|vacations|ups|uol|uno|university|unicom|uconnect|ubs|ubank|tvs|tushu|tunes|tui|tube|trv|trust|" + + "travelersinsurance|travelers|travelchannel|travel|training|trading|trade|toys|toyota|town|tours|" + + "total|toshiba|toray|top|tools|tokyo|today|tmall|tkmaxx|tjx|tjmaxx|tirol|tires|tips|tiffany|tienda|" + + "tickets|tiaa|theatre|theater|thd|teva|tennis|temasek|telefonica|telecity|tel|technology|tech|team|" + + "tdk|tci|taxi|tax|tattoo|tatar|tatamotors|target|taobao|talk|taipei|tab|systems|symantec|sydney|swiss|" + + "swiftcover|swatch|suzuki|surgery|surf|support|supply|supplies|sucks|style|study|studio|stream|store|" + + "storage|stockholm|stcgroup|stc|statoil|statefarm|statebank|starhub|star|staples|stada|srt|srl|" + + "spreadbetting|spot|sport|spiegel|space|soy|sony|song|solutions|solar|sohu|software|softbank|social|" + + "soccer|sncf|smile|smart|sling|skype|sky|skin|ski|site|singles|sina|silk|shriram|showtime|show|shouji|" + + "shopping|shop|shoes|shiksha|shia|shell|shaw|sharp|shangrila|sfr|sexy|sex|sew|seven|ses|services|" + + "sener|select|seek|security|secure|seat|search|scot|scor|scjohnson|science|schwarz|schule|school|" + + "scholarships|schmidt|schaeffler|scb|sca|sbs|sbi|saxo|save|sas|sarl|sapo|sap|sanofi|sandvikcoromant|" + + "sandvik|samsung|samsclub|salon|sale|sakura|safety|safe|saarland|ryukyu|rwe|run|ruhr|rugby|rsvp|room|" + + "rogers|rodeo|rocks|rocher|rmit|rip|rio|ril|rightathome|ricoh|richardli|rich|rexroth|reviews|review|" + + "restaurant|rest|republican|report|repair|rentals|rent|ren|reliance|reit|reisen|reise|rehab|" + + "redumbrella|redstone|red|recipes|realty|realtor|realestate|read|raid|radio|racing|qvc|quest|quebec|" + + "qpon|pwc|pub|prudential|pru|protection|property|properties|promo|progressive|prof|productions|prod|" + + "pro|prime|press|praxi|pramerica|post|porn|politie|poker|pohl|pnc|plus|plumbing|playstation|play|" + + "place|pizza|pioneer|pink|ping|pin|pid|pictures|pictet|pics|piaget|physio|photos|photography|photo|" + + "phone|philips|phd|pharmacy|pfizer|pet|pccw|pay|passagens|party|parts|partners|pars|paris|panerai|" + + "panasonic|pamperedchef|page|ovh|ott|otsuka|osaka|origins|orientexpress|organic|org|orange|oracle|" + + "open|ooo|onyourside|online|onl|ong|one|omega|ollo|oldnavy|olayangroup|olayan|okinawa|office|off|" + + "observer|obi|nyc|ntt|nrw|nra|nowtv|nowruz|now|norton|northwesternmutual|nokia|nissay|nissan|ninja|" + + "nikon|nike|nico|nhk|ngo|nfl|nexus|nextdirect|next|news|newholland|new|neustar|network|netflix|" + + "netbank|net|nec|nba|navy|natura|nationwide|name|nagoya|nadex|nab|mutuelle|mutual|museum|mtr|mtpc|mtn|" + + "msd|movistar|movie|mov|motorcycles|moto|moscow|mortgage|mormon|mopar|montblanc|monster|money|monash|" + + "mom|moi|moe|moda|mobily|mobile|mobi|mma|mls|mlb|mitsubishi|mit|mint|mini|mil|microsoft|miami|metlife|" + + "merckmsd|meo|menu|men|memorial|meme|melbourne|meet|media|med|mckinsey|mcdonalds|mcd|mba|mattel|" + + "maserati|marshalls|marriott|markets|marketing|market|map|mango|management|man|makeup|maison|maif|" + + "madrid|macys|luxury|luxe|lupin|lundbeck|ltda|ltd|lplfinancial|lpl|love|lotto|lotte|london|lol|loft|" + + "locus|locker|loans|loan|llp|llc|lixil|living|live|lipsy|link|linde|lincoln|limo|limited|lilly|like|" + + "lighting|lifestyle|lifeinsurance|life|lidl|liaison|lgbt|lexus|lego|legal|lefrak|leclerc|lease|lds|" + + "lawyer|law|latrobe|latino|lat|lasalle|lanxess|landrover|land|lancome|lancia|lancaster|lamer|" + + "lamborghini|ladbrokes|lacaixa|kyoto|kuokgroup|kred|krd|kpn|kpmg|kosher|komatsu|koeln|kiwi|kitchen|" + + "kindle|kinder|kim|kia|kfh|kerryproperties|kerrylogistics|kerryhotels|kddi|kaufen|juniper|juegos|jprs|" + + "jpmorgan|joy|jot|joburg|jobs|jnj|jmp|jll|jlc|jio|jewelry|jetzt|jeep|jcp|jcb|java|jaguar|iwc|iveco|" + + "itv|itau|istanbul|ist|ismaili|iselect|irish|ipiranga|investments|intuit|international|intel|int|" + + "insure|insurance|institute|ink|ing|info|infiniti|industries|inc|immobilien|immo|imdb|imamat|ikano|" + + "iinet|ifm|ieee|icu|ice|icbc|ibm|hyundai|hyatt|hughes|htc|hsbc|how|house|hotmail|hotels|hoteles|hot|" + + "hosting|host|hospital|horse|honeywell|honda|homesense|homes|homegoods|homedepot|holiday|holdings|" + + "hockey|hkt|hiv|hitachi|hisamitsu|hiphop|hgtv|hermes|here|helsinki|help|healthcare|health|hdfcbank|" + + "hdfc|hbo|haus|hangout|hamburg|hair|guru|guitars|guide|guge|gucci|guardian|group|grocery|gripe|green|" + + "gratis|graphics|grainger|gov|got|gop|google|goog|goodyear|goodhands|goo|golf|goldpoint|gold|godaddy|" + + "gmx|gmo|gmbh|gmail|globo|global|gle|glass|glade|giving|gives|gifts|gift|ggee|george|genting|gent|gea|" + + "gdn|gbiz|gay|garden|gap|games|game|gallup|gallo|gallery|gal|fyi|futbol|furniture|fund|fun|fujixerox|" + + "fujitsu|ftr|frontier|frontdoor|frogans|frl|fresenius|free|fox|foundation|forum|forsale|forex|ford|" + + "football|foodnetwork|food|foo|fly|flsmidth|flowers|florist|flir|flights|flickr|fitness|fit|fishing|" + + "fish|firmdale|firestone|fire|financial|finance|final|film|fido|fidelity|fiat|ferrero|ferrari|" + + "feedback|fedex|fast|fashion|farmers|farm|fans|fan|family|faith|fairwinds|fail|fage|extraspace|" + + "express|exposed|expert|exchange|everbank|events|eus|eurovision|etisalat|esurance|estate|esq|erni|" + + "ericsson|equipment|epson|epost|enterprises|engineering|engineer|energy|emerck|email|education|edu|" + + "edeka|eco|eat|earth|dvr|dvag|durban|dupont|duns|dunlop|duck|dubai|dtv|drive|download|dot|doosan|" + + "domains|doha|dog|dodge|doctor|docs|dnp|diy|dish|discover|discount|directory|direct|digital|diet|" + + "diamonds|dhl|dev|design|desi|dentist|dental|democrat|delta|deloitte|dell|delivery|degree|deals|" + + "dealer|deal|dds|dclk|day|datsun|dating|date|data|dance|dad|dabur|cyou|cymru|cuisinella|csc|cruises|" + + "cruise|crs|crown|cricket|creditunion|creditcard|credit|cpa|courses|coupons|coupon|country|corsica|" + + "coop|cool|cookingchannel|cooking|contractors|contact|consulting|construction|condos|comsec|computer|" + + "compare|company|community|commbank|comcast|com|cologne|college|coffee|codes|coach|clubmed|club|cloud|" + + "clothing|clinique|clinic|click|cleaning|claims|cityeats|city|citic|citi|citadel|cisco|circle|" + + "cipriani|church|chrysler|chrome|christmas|chloe|chintai|cheap|chat|chase|charity|channel|chanel|cfd|" + + "cfa|cern|ceo|center|ceb|cbs|cbre|cbn|cba|catholic|catering|cat|casino|cash|caseih|case|casa|cartier|" + + "cars|careers|career|care|cards|caravan|car|capitalone|capital|capetown|canon|cancerresearch|camp|" + + "camera|cam|calvinklein|call|cal|cafe|cab|bzh|buzz|buy|business|builders|build|bugatti|budapest|" + + "brussels|brother|broker|broadway|bridgestone|bradesco|box|boutique|bot|boston|bostik|bosch|boots|" + + "booking|book|boo|bond|bom|bofa|boehringer|boats|bnpparibas|bnl|bmw|bms|blue|bloomberg|blog|" + + "blockbuster|blanco|blackfriday|black|biz|bio|bingo|bing|bike|bid|bible|bharti|bet|bestbuy|best|" + + "berlin|bentley|beer|beauty|beats|bcn|bcg|bbva|bbt|bbc|bayern|bauhaus|basketball|baseball|bargains|" + + "barefoot|barclays|barclaycard|barcelona|bar|bank|band|bananarepublic|banamex|baidu|baby|azure|axa|" + + "aws|avianca|autos|auto|author|auspost|audio|audible|audi|auction|attorney|athleta|associates|asia|" + + "asda|arte|art|arpa|army|archi|aramco|arab|aquarelle|apple|app|apartments|aol|anz|anquan|android|" + + "analytics|amsterdam|amica|amfam|amex|americanfamily|americanexpress|alstom|alsace|ally|allstate|" + + "allfinanz|alipay|alibaba|alfaromeo|akdn|airtel|airforce|airbus|aigo|aig|agency|agakhan|africa|afl|" + + "afamilycompany|aetna|aero|aeg|adult|ads|adac|actor|active|aco|accountants|accountant|accenture|" + + "academy|abudhabi|abogado|able|abc|abbvie|abbott|abb|abarth|aarp|aaa|onion" + + ")(?=[^a-z0-9@+-]|$))" static let TWUValidCCTLD = "(?:(?:" - + "한국|香港|澳門|新加坡|台灣|台湾|中國|中国|გე|ລາວ|ไทย|ලංකා|ഭാരതം|ಭಾರತ|భారత్|சிங்கப்பூர்|இலங்கை|இந்தியா|ଭାରତ|ભારત|ਭਾਰਤ|" - + "ভাৰত|ভারত|বাংলা|भारोत|भारतम्|भारत|ڀارت|پاکستان|موريتانيا|مليسيا|مصر|قطر|فلسطين|عمان|عراق|سورية|سودان|" - + "تونس|بھارت|بارت|ایران|امارات|المغرب|السعودية|الجزائر|البحرين|الاردن|հայ|қаз|укр|срб|рф|мон|мкд|ею|" - + "бел|бг|ευ|ελ|zw|zm|za|yt|ye|ws|wf|vu|vn|vi|vg|ve|vc|va|uz|uy|us|um|uk|ug|ua|tz|tw|tv|tt|tr|tp|to|tn|" - + "tm|tl|tk|tj|th|tg|tf|td|tc|sz|sy|sx|sv|su|st|ss|sr|so|sn|sm|sl|sk|sj|si|sh|sg|se|sd|sc|sb|sa|rw|ru|" - + "rs|ro|re|qa|py|pw|pt|ps|pr|pn|pm|pl|pk|ph|pg|pf|pe|pa|om|nz|nu|nr|np|no|nl|ni|ng|nf|ne|nc|na|mz|my|" - + "mx|mw|mv|mu|mt|ms|mr|mq|mp|mo|mn|mm|ml|mk|mh|mg|mf|me|md|mc|ma|ly|lv|lu|lt|ls|lr|lk|li|lc|lb|la|kz|" - + "ky|kw|kr|kp|kn|km|ki|kh|kg|ke|jp|jo|jm|je|it|is|ir|iq|io|in|im|il|ie|id|hu|ht|hr|hn|hm|hk|gy|gw|gu|" - + "gt|gs|gr|gq|gp|gn|gm|gl|gi|gh|gg|gf|ge|gd|gb|ga|fr|fo|fm|fk|fj|fi|eu|et|es|er|eh|eg|ee|ec|dz|do|dm|" - + "dk|dj|de|cz|cy|cx|cw|cv|cu|cr|co|cn|cm|cl|ck|ci|ch|cg|cf|cd|cc|ca|bz|by|bw|bv|bt|bs|br|bq|bo|bn|bm|" - + "bl|bj|bi|bh|bg|bf|be|bd|bb|ba|az|ax|aw|au|at|as|ar|aq|ao|an|am|al|ai|ag|af|ae|ad|ac" - + ")(?=[^a-z0-9@+-]|$))" + + "한국|香港|澳門|新加坡|台灣|台湾|中國|中国|გე|ລາວ|ไทย|ලංකා|ഭാരതം|ಭಾರತ|భారత్|சிங்கப்பூர்|இலங்கை|இந்தியா|ଭାରତ|ભારત|ਭਾਰਤ|" + + "ভাৰত|ভারত|বাংলা|भारोत|भारतम्|भारत|ڀارت|پاکستان|موريتانيا|مليسيا|مصر|قطر|فلسطين|عمان|عراق|سورية|سودان|" + + "تونس|بھارت|بارت|ایران|امارات|المغرب|السعودية|الجزائر|البحرين|الاردن|հայ|қаз|укр|срб|рф|мон|мкд|ею|" + + "бел|бг|ευ|ελ|zw|zm|za|yt|ye|ws|wf|vu|vn|vi|vg|ve|vc|va|uz|uy|us|um|uk|ug|ua|tz|tw|tv|tt|tr|tp|to|tn|" + + "tm|tl|tk|tj|th|tg|tf|td|tc|sz|sy|sx|sv|su|st|ss|sr|so|sn|sm|sl|sk|sj|si|sh|sg|se|sd|sc|sb|sa|rw|ru|" + + "rs|ro|re|qa|py|pw|pt|ps|pr|pn|pm|pl|pk|ph|pg|pf|pe|pa|om|nz|nu|nr|np|no|nl|ni|ng|nf|ne|nc|na|mz|my|" + + "mx|mw|mv|mu|mt|ms|mr|mq|mp|mo|mn|mm|ml|mk|mh|mg|mf|me|md|mc|ma|ly|lv|lu|lt|ls|lr|lk|li|lc|lb|la|kz|" + + "ky|kw|kr|kp|kn|km|ki|kh|kg|ke|jp|jo|jm|je|it|is|ir|iq|io|in|im|il|ie|id|hu|ht|hr|hn|hm|hk|gy|gw|gu|" + + "gt|gs|gr|gq|gp|gn|gm|gl|gi|gh|gg|gf|ge|gd|gb|ga|fr|fo|fm|fk|fj|fi|eu|et|es|er|eh|eg|ee|ec|dz|do|dm|" + + "dk|dj|de|cz|cy|cx|cw|cv|cu|cr|co|cn|cm|cl|ck|ci|ch|cg|cf|cd|cc|ca|bz|by|bw|bv|bt|bs|br|bq|bo|bn|bm|" + + "bl|bj|bi|bh|bg|bf|be|bd|bb|ba|az|ax|aw|au|at|as|ar|aq|ao|an|am|al|ai|ag|af|ae|ad|ac" + + ")(?=[^a-z0-9@+-]|$))" static let TWUValidTCOURL = "^https?://t\\.co/([a-z0-9]+)" static let TWUValidURLPath = "(?:(?:\(TWUValidGeneralURLPathChars)*" - + "(?:\(TWUValidURLBalancedParens)\(TWUValidGeneralURLPathChars)*)*\(TWUValidURLPathEndingChars)" - + ")|(?:\(TWUValidGeneralURLPathChars)+/))" + + "(?:\(TWUValidURLBalancedParens)\(TWUValidGeneralURLPathChars)*)*\(TWUValidURLPathEndingChars)" + + ")|(?:\(TWUValidGeneralURLPathChars)+/))" static let emojiPattern = "(?:\u{0001f468}\u{0001f3fb}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fc}-\u{0001f3ff}]|\u{0001f468}\u{0001f3fc}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}\u{0001f3fd}-\u{0001f3ff}]|\u{0001f468}\u{0001f3fd}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}\u{0001f3fc}\u{0001f3fe}\u{0001f3ff}]|\u{0001f468}\u{0001f3fe}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}-\u{0001f3fd}\u{0001f3ff}]|\u{0001f468}\u{0001f3ff}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}-\u{0001f3fe}]|\u{0001f469}\u{0001f3fb}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fc}-\u{0001f3ff}]|\u{0001f469}\u{0001f3fb}\u{200d}\u{0001f91d}\u{200d}\u{0001f469}[\u{0001f3fc}-\u{0001f3ff}]|\u{0001f469}\u{0001f3fc}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}\u{0001f3fd}-\u{0001f3ff}]|\u{0001f469}\u{0001f3fc}\u{200d}\u{0001f91d}\u{200d}\u{0001f469}[\u{0001f3fb}\u{0001f3fd}-\u{0001f3ff}]|\u{0001f469}\u{0001f3fd}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}\u{0001f3fc}\u{0001f3fe}\u{0001f3ff}]|\u{0001f469}\u{0001f3fd}\u{200d}\u{0001f91d}\u{200d}\u{0001f469}[\u{0001f3fb}\u{0001f3fc}\u{0001f3fe}\u{0001f3ff}]|\u{0001f469}\u{0001f3fe}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}-\u{0001f3fd}\u{0001f3ff}]|\u{0001f469}\u{0001f3fe}\u{200d}\u{0001f91d}\u{200d}\u{0001f469}[\u{0001f3fb}-\u{0001f3fd}\u{0001f3ff}]|\u{0001f469}\u{0001f3ff}\u{200d}\u{0001f91d}\u{200d}\u{0001f468}[\u{0001f3fb}-\u{0001f3fe}]|\u{0001f469}\u{0001f3ff}\u{200d}\u{0001f91d}\u{200d}\u{0001f469}[\u{0001f3fb}-\u{0001f3fe}]|\u{0001f9d1}\u{0001f3fb}\u{200d}\u{0001f91d}\u{200d}\u{0001f9d1}[\u{0001f3fb}-\u{0001f3ff}]|\u{0001f9d1}\u{0001f3fc}\u{200d}\u{0001f91d}\u{200d}\u{0001f9d1}[\u{0001f3fb}-\u{0001f3ff}]|\u{0001f9d1}\u{0001f3fd}\u{200d}\u{0001f91d}\u{200d}\u{0001f9d1}[\u{0001f3fb}-\u{0001f3ff}]|\u{0001f9d1}\u{0001f3fe}\u{200d}\u{0001f91d}\u{200d}\u{0001f9d1}[\u{0001f3fb}-\u{0001f3ff}]|\u{0001f9d1}\u{0001f3ff}\u{200d}\u{0001f91d}\u{200d}\u{0001f9d1}[\u{0001f3fb}-\u{0001f3ff}]|\u{0001f9d1}\u{200d}\u{0001f91d}\u{200d}\u{0001f9d1}|\u{0001f46b}[\u{0001f3fb}-\u{0001f3ff}]|\u{0001f46c}[\u{0001f3fb}-\u{0001f3ff}]|\u{0001f46d}[\u{0001f3fb}-\u{0001f3ff}]|[\u{0001f46b}-\u{0001f46d}])|[\u{0001f468}\u{0001f469}\u{0001f9d1}][\u{0001f3fb}-\u{0001f3ff}]?\u{200d}(?:\u{2695}\u{fe0f}|\u{2696}\u{fe0f}|\u{2708}\u{fe0f}|[\u{0001f33e}\u{0001f373}\u{0001f393}\u{0001f3a4}\u{0001f3a8}\u{0001f3eb}\u{0001f3ed}\u{0001f4bb}\u{0001f4bc}\u{0001f527}\u{0001f52c}\u{0001f680}\u{0001f692}\u{0001f9af}-\u{0001f9b3}\u{0001f9bc}\u{0001f9bd}])|[\u{26f9}\u{0001f3cb}\u{0001f3cc}\u{0001f574}\u{0001f575}]([\u{fe0f}\u{0001f3fb}-\u{0001f3ff}]\u{200d}[\u{2640}\u{2642}]\u{fe0f})|[\u{0001f3c3}\u{0001f3c4}\u{0001f3ca}\u{0001f46e}\u{0001f471}\u{0001f473}\u{0001f477}\u{0001f481}\u{0001f482}\u{0001f486}\u{0001f487}\u{0001f645}-\u{0001f647}\u{0001f64b}\u{0001f64d}\u{0001f64e}\u{0001f6a3}\u{0001f6b4}-\u{0001f6b6}\u{0001f926}\u{0001f935}\u{0001f937}-\u{0001f939}\u{0001f93d}\u{0001f93e}\u{0001f9b8}\u{0001f9b9}\u{0001f9cd}-\u{0001f9cf}\u{0001f9d6}-\u{0001f9dd}][\u{0001f3fb}-\u{0001f3ff}]?\u{200d}[\u{2640}\u{2642}]\u{fe0f}|(?:\u{0001f468}\u{200d}\u{2764}\u{fe0f}\u{200d}\u{0001f48b}\u{200d}\u{0001f468}|\u{0001f469}\u{200d}\u{2764}\u{fe0f}\u{200d}\u{0001f48b}\u{200d}[\u{0001f468}\u{0001f469}]|\u{0001f468}\u{200d}\u{0001f468}\u{200d}\u{0001f466}\u{200d}\u{0001f466}|\u{0001f468}\u{200d}\u{0001f468}\u{200d}\u{0001f467}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f468}\u{200d}\u{0001f469}\u{200d}\u{0001f466}\u{200d}\u{0001f466}|\u{0001f468}\u{200d}\u{0001f469}\u{200d}\u{0001f467}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f469}\u{200d}\u{0001f469}\u{200d}\u{0001f466}\u{200d}\u{0001f466}|\u{0001f469}\u{200d}\u{0001f469}\u{200d}\u{0001f467}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f468}\u{200d}\u{2764}\u{fe0f}\u{200d}\u{0001f468}|\u{0001f469}\u{200d}\u{2764}\u{fe0f}\u{200d}[\u{0001f468}\u{0001f469}]|\u{0001f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}|\u{0001f468}\u{200d}\u{0001f466}\u{200d}\u{0001f466}|\u{0001f468}\u{200d}\u{0001f467}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f468}\u{200d}\u{0001f468}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f468}\u{200d}\u{0001f469}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f469}\u{200d}\u{0001f466}\u{200d}\u{0001f466}|\u{0001f469}\u{200d}\u{0001f467}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f469}\u{200d}\u{0001f469}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f3f3}\u{fe0f}\u{200d}\u{0001f308}|\u{0001f3f4}\u{200d}\u{2620}\u{fe0f}|\u{0001f46f}\u{200d}\u{2640}\u{fe0f}|\u{0001f46f}\u{200d}\u{2642}\u{fe0f}|\u{0001f93c}\u{200d}\u{2640}\u{fe0f}|\u{0001f93c}\u{200d}\u{2642}\u{fe0f}|\u{0001f9de}\u{200d}\u{2640}\u{fe0f}|\u{0001f9de}\u{200d}\u{2642}\u{fe0f}|\u{0001f9df}\u{200d}\u{2640}\u{fe0f}|\u{0001f9df}\u{200d}\u{2642}\u{fe0f}|\u{0001f415}\u{200d}\u{0001f9ba}|\u{0001f441}\u{200d}\u{0001f5e8}|\u{0001f468}\u{200d}[\u{0001f466}\u{0001f467}]|\u{0001f469}\u{200d}[\u{0001f466}\u{0001f467}])|[#*0-9]\u{fe0f}?\u{20e3}|(?:[©®\u{2122}\u{265f}]\u{fe0f})|[\u{203c}\u{2049}\u{2139}\u{2194}-\u{2199}\u{21a9}\u{21aa}\u{231a}\u{231b}\u{2328}\u{23cf}\u{23ed}-\u{23ef}\u{23f1}\u{23f2}\u{23f8}-\u{23fa}\u{24c2}\u{25aa}\u{25ab}\u{25b6}\u{25c0}\u{25fb}-\u{25fe}\u{2600}-\u{2604}\u{260e}\u{2611}\u{2614}\u{2615}\u{2618}\u{2620}\u{2622}\u{2623}\u{2626}\u{262a}\u{262e}\u{262f}\u{2638}-\u{263a}\u{2640}\u{2642}\u{2648}-\u{2653}\u{2660}\u{2663}\u{2665}\u{2666}\u{2668}\u{267b}\u{267f}\u{2692}-\u{2697}\u{2699}\u{269b}\u{269c}\u{26a0}\u{26a1}\u{26a7}\u{26aa}\u{26ab}\u{26b0}\u{26b1}\u{26bd}\u{26be}\u{26c4}\u{26c5}\u{26c8}\u{26cf}\u{26d1}\u{26d3}\u{26d4}\u{26e9}\u{26ea}\u{26f0}-\u{26f5}\u{26f8}\u{26fa}\u{26fd}\u{2702}\u{2708}\u{2709}\u{270f}\u{2712}\u{2714}\u{2716}\u{271d}\u{2721}\u{2733}\u{2734}\u{2744}\u{2747}\u{2757}\u{2763}\u{2764}\u{27a1}\u{2934}\u{2935}\u{2b05}-\u{2b07}\u{2b1b}\u{2b1c}\u{2b50}\u{2b55}\u{3030}\u{303d}\u{3297}\u{3299}\u{0001f004}\u{0001f170}\u{0001f171}\u{0001f17e}\u{0001f17f}\u{0001f202}\u{0001f21a}\u{0001f22f}\u{0001f237}\u{0001f321}\u{0001f324}-\u{0001f32c}\u{0001f336}\u{0001f37d}\u{0001f396}\u{0001f397}\u{0001f399}-\u{0001f39b}\u{0001f39e}\u{0001f39f}\u{0001f3cd}\u{0001f3ce}\u{0001f3d4}-\u{0001f3df}\u{0001f3f3}\u{0001f3f5}\u{0001f3f7}\u{0001f43f}\u{0001f441}\u{0001f4fd}\u{0001f549}\u{0001f54a}\u{0001f56f}\u{0001f570}\u{0001f573}\u{0001f576}-\u{0001f579}\u{0001f587}\u{0001f58a}-\u{0001f58d}\u{0001f5a5}\u{0001f5a8}\u{0001f5b1}\u{0001f5b2}\u{0001f5bc}\u{0001f5c2}-\u{0001f5c4}\u{0001f5d1}-\u{0001f5d3}\u{0001f5dc}-\u{0001f5de}\u{0001f5e1}\u{0001f5e3}\u{0001f5e8}\u{0001f5ef}\u{0001f5f3}\u{0001f5fa}\u{0001f6cb}\u{0001f6cd}-\u{0001f6cf}\u{0001f6e0}-\u{0001f6e5}\u{0001f6e9}\u{0001f6f0}\u{0001f6f3}](?:\u{fe0f}|(?!\u{fe0e}))|(?:[\u{261d}\u{26f7}\u{26f9}\u{270c}\u{270d}\u{0001f3cb}\u{0001f3cc}\u{0001f574}\u{0001f575}\u{0001f590}](?:\u{fe0f}|(?!\u{fe0e}))|[\u{270a}\u{270b}\u{0001f385}\u{0001f3c2}-\u{0001f3c4}\u{0001f3c7}\u{0001f3ca}\u{0001f442}\u{0001f443}\u{0001f446}-\u{0001f450}\u{0001f466}-\u{0001f469}\u{0001f46e}\u{0001f470}-\u{0001f478}\u{0001f47c}\u{0001f481}-\u{0001f483}\u{0001f485}-\u{0001f487}\u{0001f4aa}\u{0001f57a}\u{0001f595}\u{0001f596}\u{0001f645}-\u{0001f647}\u{0001f64b}-\u{0001f64f}\u{0001f6a3}\u{0001f6b4}-\u{0001f6b6}\u{0001f6c0}\u{0001f6cc}\u{0001f90f}\u{0001f918}-\u{0001f91c}\u{0001f91e}\u{0001f91f}\u{0001f926}\u{0001f930}-\u{0001f939}\u{0001f93d}\u{0001f93e}\u{0001f9b5}\u{0001f9b6}\u{0001f9b8}\u{0001f9b9}\u{0001f9bb}\u{0001f9cd}-\u{0001f9cf}\u{0001f9d1}-\u{0001f9dd}])[\u{0001f3fb}-\u{0001f3ff}]?|(?:\u{0001f3f4}\u{000e0067}\u{000e0062}\u{000e0065}\u{000e006e}\u{000e0067}\u{000e007f}|\u{0001f3f4}\u{000e0067}\u{000e0062}\u{000e0073}\u{000e0063}\u{000e0074}\u{000e007f}|\u{0001f3f4}\u{000e0067}\u{000e0062}\u{000e0077}\u{000e006c}\u{000e0073}\u{000e007f}|\u{0001f1e6}[\u{0001f1e8}-\u{0001f1ec}\u{0001f1ee}\u{0001f1f1}\u{0001f1f2}\u{0001f1f4}\u{0001f1f6}-\u{0001f1fa}\u{0001f1fc}\u{0001f1fd}\u{0001f1ff}]|\u{0001f1e7}[\u{0001f1e6}\u{0001f1e7}\u{0001f1e9}-\u{0001f1ef}\u{0001f1f1}-\u{0001f1f4}\u{0001f1f6}-\u{0001f1f9}\u{0001f1fb}\u{0001f1fc}\u{0001f1fe}\u{0001f1ff}]|\u{0001f1e8}[\u{0001f1e6}\u{0001f1e8}\u{0001f1e9}\u{0001f1eb}-\u{0001f1ee}\u{0001f1f0}-\u{0001f1f5}\u{0001f1f7}\u{0001f1fa}-\u{0001f1ff}]|\u{0001f1e9}[\u{0001f1ea}\u{0001f1ec}\u{0001f1ef}\u{0001f1f0}\u{0001f1f2}\u{0001f1f4}\u{0001f1ff}]|\u{0001f1ea}[\u{0001f1e6}\u{0001f1e8}\u{0001f1ea}\u{0001f1ec}\u{0001f1ed}\u{0001f1f7}-\u{0001f1fa}]|\u{0001f1eb}[\u{0001f1ee}-\u{0001f1f0}\u{0001f1f2}\u{0001f1f4}\u{0001f1f7}]|\u{0001f1ec}[\u{0001f1e6}\u{0001f1e7}\u{0001f1e9}-\u{0001f1ee}\u{0001f1f1}-\u{0001f1f3}\u{0001f1f5}-\u{0001f1fa}\u{0001f1fc}\u{0001f1fe}]|\u{0001f1ed}[\u{0001f1f0}\u{0001f1f2}\u{0001f1f3}\u{0001f1f7}\u{0001f1f9}\u{0001f1fa}]|\u{0001f1ee}[\u{0001f1e8}-\u{0001f1ea}\u{0001f1f1}-\u{0001f1f4}\u{0001f1f6}-\u{0001f1f9}]|\u{0001f1ef}[\u{0001f1ea}\u{0001f1f2}\u{0001f1f4}\u{0001f1f5}]|\u{0001f1f0}[\u{0001f1ea}\u{0001f1ec}-\u{0001f1ee}\u{0001f1f2}\u{0001f1f3}\u{0001f1f5}\u{0001f1f7}\u{0001f1fc}\u{0001f1fe}\u{0001f1ff}]|\u{0001f1f1}[\u{0001f1e6}-\u{0001f1e8}\u{0001f1ee}\u{0001f1f0}\u{0001f1f7}-\u{0001f1fb}\u{0001f1fe}]|\u{0001f1f2}[\u{0001f1e6}\u{0001f1e8}-\u{0001f1ed}\u{0001f1f0}-\u{0001f1ff}]|\u{0001f1f3}[\u{0001f1e6}\u{0001f1e8}\u{0001f1ea}-\u{0001f1ec}\u{0001f1ee}\u{0001f1f1}\u{0001f1f4}\u{0001f1f5}\u{0001f1f7}\u{0001f1fa}\u{0001f1ff}]|\u{0001f1f4}\u{0001f1f2}|\u{0001f1f5}[\u{0001f1e6}\u{0001f1ea}-\u{0001f1ed}\u{0001f1f0}-\u{0001f1f3}\u{0001f1f7}-\u{0001f1f9}\u{0001f1fc}\u{0001f1fe}]|\u{0001f1f6}\u{0001f1e6}|\u{0001f1f7}[\u{0001f1ea}\u{0001f1f4}\u{0001f1f8}\u{0001f1fa}\u{0001f1fc}]|\u{0001f1f8}[\u{0001f1e6}-\u{0001f1ea}\u{0001f1ec}-\u{0001f1f4}\u{0001f1f7}-\u{0001f1f9}\u{0001f1fb}\u{0001f1fd}-\u{0001f1ff}]|\u{0001f1f9}[\u{0001f1e6}\u{0001f1e8}\u{0001f1e9}\u{0001f1eb}-\u{0001f1ed}\u{0001f1ef}-\u{0001f1f4}\u{0001f1f7}\u{0001f1f9}\u{0001f1fb}\u{0001f1fc}\u{0001f1ff}]|\u{0001f1fa}[\u{0001f1e6}\u{0001f1ec}\u{0001f1f2}\u{0001f1f3}\u{0001f1f8}\u{0001f1fe}\u{0001f1ff}]|\u{0001f1fb}[\u{0001f1e6}\u{0001f1e8}\u{0001f1ea}\u{0001f1ec}\u{0001f1ee}\u{0001f1f3}\u{0001f1fa}]|\u{0001f1fc}[\u{0001f1eb}\u{0001f1f8}]|\u{0001f1fd}\u{0001f1f0}|\u{0001f1fe}[\u{0001f1ea}\u{0001f1f9}]|\u{0001f1ff}[\u{0001f1e6}\u{0001f1f2}\u{0001f1fc}]|[\u{23e9}-\u{23ec}\u{23f0}\u{23f3}\u{267e}\u{26ce}\u{2705}\u{2728}\u{274c}\u{274e}\u{2753}-\u{2755}\u{2795}-\u{2797}\u{27b0}\u{27bf}\u{e50a}\u{0001f0cf}\u{0001f18e}\u{0001f191}-\u{0001f19a}\u{0001f1e6}-\u{0001f1ff}\u{0001f201}\u{0001f232}-\u{0001f236}\u{0001f238}-\u{0001f23a}\u{0001f250}\u{0001f251}\u{0001f300}-\u{0001f320}\u{0001f32d}-\u{0001f335}\u{0001f337}-\u{0001f37c}\u{0001f37e}-\u{0001f384}\u{0001f386}-\u{0001f393}\u{0001f3a0}-\u{0001f3c1}\u{0001f3c5}\u{0001f3c6}\u{0001f3c8}\u{0001f3c9}\u{0001f3cf}-\u{0001f3d3}\u{0001f3e0}-\u{0001f3f0}\u{0001f3f4}\u{0001f3f8}-\u{0001f43e}\u{0001f440}\u{0001f444}\u{0001f445}\u{0001f451}-\u{0001f465}\u{0001f46a}\u{0001f46f}\u{0001f479}-\u{0001f47b}\u{0001f47d}-\u{0001f480}\u{0001f484}\u{0001f488}-\u{0001f4a9}\u{0001f4ab}-\u{0001f4fc}\u{0001f4ff}-\u{0001f53d}\u{0001f54b}-\u{0001f54e}\u{0001f550}-\u{0001f567}\u{0001f5a4}\u{0001f5fb}-\u{0001f644}\u{0001f648}-\u{0001f64a}\u{0001f680}-\u{0001f6a2}\u{0001f6a4}-\u{0001f6b3}\u{0001f6b7}-\u{0001f6bf}\u{0001f6c1}-\u{0001f6c5}\u{0001f6d0}-\u{0001f6d2}\u{0001f6d5}\u{0001f6eb}\u{0001f6ec}\u{0001f6f4}-\u{0001f6fa}\u{0001f7e0}-\u{0001f7eb}\u{0001f90d}\u{0001f90e}\u{0001f910}-\u{0001f917}\u{0001f91d}\u{0001f920}-\u{0001f925}\u{0001f927}-\u{0001f92f}\u{0001f93a}\u{0001f93c}\u{0001f93f}-\u{0001f945}\u{0001f947}-\u{0001f971}\u{0001f973}-\u{0001f976}\u{0001f97a}-\u{0001f9a2}\u{0001f9a5}-\u{0001f9aa}\u{0001f9ae}-\u{0001f9b4}\u{0001f9b7}\u{0001f9ba}\u{0001f9bc}-\u{0001f9ca}\u{0001f9d0}\u{0001f9de}-\u{0001f9ff}\u{0001fa70}-\u{0001fa73}\u{0001fa78}-\u{0001fa7a}\u{0001fa80}-\u{0001fa82}\u{0001fa90}-\u{0001fa95}])|\u{fe0f}" } - } extension String { @@ -783,8 +779,8 @@ extension String { let matches = regex.matches(in: self, options: [], range: range) return matches.count == 1 - && matches[0].range.location != NSNotFound - && NSMaxRange(matches[0].range) <= self.utf16.count + && matches[0].range.location != NSNotFound + && NSMaxRange(matches[0].range) <= utf16.count } catch { return false } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/ReferencedTweetView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/ReferencedTweetView.swift index f467aa75a8..2339e3bb15 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/ReferencedTweetView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/ReferencedTweetView.swift @@ -1,5 +1,5 @@ -import UIKit import ComponentKit +import UIKit class ReferencedTweetView: UIView { private static let titleFont: UIFont = .caption @@ -35,7 +35,8 @@ class ReferencedTweetView: UIView { bodyView.textColor = .themeLeah } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -49,5 +50,4 @@ class ReferencedTweetView: UIView { return ceil(Self.sideMargin + Self.titleFont.lineHeight + Self.insideMargin + textHeight + Self.sideMargin) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetAttachmentView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetAttachmentView.swift index b0c2e35d54..e36f9fd6e9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetAttachmentView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetAttachmentView.swift @@ -1,5 +1,5 @@ -import UIKit import ComponentKit +import UIKit class TweetAttachmentView: UIView { private static let imageAttachmentHeight: CGFloat = 180 @@ -24,31 +24,32 @@ class TweetAttachmentView: UIView { imageTransparencyView.snp.makeConstraints { maker in maker.edges.equalToSuperview() } - + imageTransparencyView.cornerRadius = .cornerRadius4 imageTransparencyView.layer.cornerCurve = .continuous imageTransparencyView.backgroundColor = UIColor(white: 0, alpha: 0.5) - + imageView.addSubview(videoPlayImageView) videoPlayImageView.snp.makeConstraints { maker in maker.center.equalToSuperview() maker.width.equalTo(48) } - + videoPlayImageView.image = UIImage(named: "play_48")?.withTintColor(.white) addSubview(pollView) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func bind(attachment: Tweet.Attachment) { switch attachment { - case .photo(let url): bindPhoto(url: url) - case .video(let previewImageUrl): bindVideo(previewImageUrl: previewImageUrl) - case .poll(let options): bindPoll(options: options) + case let .photo(url): bindPhoto(url: url) + case let .video(previewImageUrl): bindVideo(previewImageUrl: previewImageUrl) + case let .poll(options): bindPoll(options: options) } } @@ -97,9 +98,8 @@ class TweetAttachmentView: UIView { static func height(attachment: Tweet.Attachment, containerWidth: CGFloat) -> CGFloat { switch attachment { - case .photo, .video: return Self.imageAttachmentHeight - case .poll(let options): return TweetPollView.height(options: options, containerWidth: containerWidth) + case .photo, .video: return imageAttachmentHeight + case let .poll(options): return TweetPollView.height(options: options, containerWidth: containerWidth) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetPollView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetPollView.swift index f32b8a2658..c21adc0397 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetPollView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinTweets/Views/TweetPollView.swift @@ -1,5 +1,5 @@ -import UIKit import ThemeKit +import UIKit class TweetPollView: UIView { private static let pollOptionHeight: CGFloat = 28 @@ -21,7 +21,8 @@ class TweetPollView: UIView { stackView.spacing = .margin8 } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -68,7 +69,7 @@ class TweetPollView: UIView { label.text = option.label label.font = .captionSB - if let mostVotesOption = mostVotesOption, mostVotesOption.position == option.position { + if let mostVotesOption, mostVotesOption.position == option.position { votesView.backgroundColor = .themeLaguna label.textColor = .themeClaude } else { @@ -89,8 +90,7 @@ class TweetPollView: UIView { } } - static func height(options: [(position: Int, label: String, votes: Int)], containerWidth: CGFloat) -> CGFloat { - (Self.pollOptionHeight + .margin8) * CGFloat(options.count) - .margin8 + static func height(options: [(position: Int, label: String, votes: Int)], containerWidth _: CGFloat) -> CGFloat { + (pollOptionHeight + .margin8) * CGFloat(options.count) - .margin8 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorFactory.swift index 8bbad3172c..af2011da37 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorFactory.swift @@ -1,6 +1,6 @@ -import UIKit -import UIExtensions import Chart +import UIExtensions +import UIKit class ChartIndicatorFactory { static let precalculatedColor = [UIColor.themeYellowD] @@ -15,16 +15,16 @@ class ChartIndicatorFactory { } static let rsiConfiguration = ChartIndicator.LineConfiguration( - color: color(.themeYellowD), - width: 1 + color: color(.themeYellowD), + width: 1 ) static let macdConfiguration = MacdIndicator.Configuration( - fastColor: color(UIColor(hex: 0x3372FF)), - longColor: color(.themeYellowD), - positiveColor: color(.themeGreenD), - negativeColor: color(.themeRedD), - width: 2, - signalWidth: 1 + fastColor: color(UIColor(hex: 0x3372FF)), + longColor: color(.themeYellowD), + positiveColor: color(.themeGreenD), + negativeColor: color(.themeRedD), + width: 2, + signalWidth: 1 ) private static func color(_ color: UIColor, alpha: CGFloat = 0.5) -> ChartColor { @@ -36,44 +36,43 @@ class ChartIndicatorFactory { let maEnabledArray = [true, true, subscribed] let maIndicators = maPeriods.enumerated().map { index, period in MaIndicator( - id: "MA", - index: index, - enabled: maEnabledArray[index], - period: period, - type: .ema, - configuration: maConfiguration(index)) + id: "MA", + index: index, + enabled: maEnabledArray[index], + period: period, + type: .ema, + configuration: maConfiguration(index) + ) } indicators.append(contentsOf: maIndicators) indicators.append(contentsOf: [ RsiIndicator( - id: ChartIndicator.AbstractType.rsi.rawValue, - index: 0, - enabled: subscribed, - period: rsiPeriod, - configuration: rsiConfiguration), + id: ChartIndicator.AbstractType.rsi.rawValue, + index: 0, + enabled: subscribed, + period: rsiPeriod, + configuration: rsiConfiguration + ), MacdIndicator( - id: ChartIndicator.AbstractType.macd.rawValue, - index: 0, - enabled: false, - fast: macdPeriod[0], - slow: macdPeriod[1], - signal: macdPeriod[2], - configuration: macdConfiguration - ) + id: ChartIndicator.AbstractType.macd.rawValue, + index: 0, + enabled: false, + fast: macdPeriod[0], + slow: macdPeriod[1], + signal: macdPeriod[2], + configuration: macdConfiguration + ), ]) return indicators } - } extension ChartIndicatorFactory { - struct MacdColor { let fast: UIColor let slow: UIColor let positive: UIColor let negative: UIColor } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsRepository.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsRepository.swift index 2b0238152e..8f0847d5a6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsRepository.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsRepository.swift @@ -105,9 +105,9 @@ extension ChartIndicatorsRepository { } } return BackupIndicators( - ma: ma, - rsi: rsi, - macd: macd + ma: ma, + rsi: rsi, + macd: macd ) } @@ -142,17 +142,17 @@ extension ChartIndicatorsRepository { } backup.macd.enumerated().forEach { index, element in indicators.append( - MacdIndicator( - id: "MACD", - index: index, - enabled: element.enabled, - fast: element.fast, - slow: element.slow, - signal: element.signal, - onChart: false, - single: true, - configuration: ChartIndicatorFactory.macdConfiguration - ) + MacdIndicator( + id: "MACD", + index: index, + enabled: element.enabled, + fast: element.fast, + slow: element.slow, + signal: element.signal, + onChart: false, + single: true, + configuration: ChartIndicatorFactory.macdConfiguration + ) ) } set(indicators: indicators) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsService.swift index 7422fb8f29..df2987b695 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsService.swift @@ -1,6 +1,6 @@ -import Foundation import Chart import Combine +import Foundation import HsExtensions import MarketKit @@ -22,29 +22,29 @@ class ChartIndicatorsService { self.subscriptionManager = subscriptionManager repository.updatedPublisher - .sink { [weak self] in - self?.sync() - } - .store(in: &cancellables) + .sink { [weak self] in + self?.sync() + } + .store(in: &cancellables) chartPointFetcher.pointsUpdatedPublisher - .sink { [weak self] in - self?.sync() - } - .store(in: &cancellables) + .sink { [weak self] in + self?.sync() + } + .store(in: &cancellables) subscriptionManager.$isAuthenticated - .sink { [weak self] _ in - self?.sync() - } - .store(in: &cancellables) + .sink { [weak self] _ in + self?.sync() + } + .store(in: &cancellables) sync() } private func calculateInsufficient(indicator: ChartIndicator, points: [ChartPoint]?) -> Bool { var insufficientData = false - if let points = points, indicator.enabled { + if let points, indicator.enabled { let minimumPoints = indicator.greatestPeriod + Self.minimumIndicatorPoints insufficientData = minimumPoints <= points.count } @@ -58,15 +58,14 @@ class ChartIndicatorsService { items = userIndicators.map { indicator in IndicatorItem( - indicator: indicator, - insufficientData: calculateInsufficient(indicator: indicator, points: points)) + indicator: indicator, + insufficientData: calculateInsufficient(indicator: indicator, points: points) + ) } } - } extension ChartIndicatorsService { - func set(enabled: Bool, id: String, index: Int) { guard let itemIndex = items.firstIndex(where: { $0.indicator.id == id && $0.indicator.index == index }) else { return @@ -89,16 +88,16 @@ extension ChartIndicatorsService { } items[itemIndex] = IndicatorItem( + indicator: newItemIndicator, + insufficientData: calculateInsufficient( indicator: newItemIndicator, - insufficientData: calculateInsufficient( - indicator: newItemIndicator, - points: chartPointFetcher.points.data - ) + points: chartPointFetcher.points.data + ) ) } func saveIndicators() { - repository.set(indicators: items.map { $0.indicator }) + repository.set(indicators: items.map(\.indicator)) } func indicator(id: String, index: Int) -> ChartIndicator? { @@ -116,14 +115,11 @@ extension ChartIndicatorsService { items[index] = IndicatorItem(indicator: indicator, insufficientData: items[index].insufficientData) } - } extension ChartIndicatorsService { - struct IndicatorItem { let indicator: ChartIndicator let insufficientData: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewController.swift index 89c7053420..2b43df0f45 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewController.swift @@ -1,11 +1,10 @@ -import Combine -import UIKit -import SnapKit import Chart +import Combine import ComponentKit -import ThemeKit import SectionsTableView - +import SnapKit +import ThemeKit +import UIKit class ChartIndicatorsViewController: ThemeViewController { private let viewModel: ChartIndicatorsViewModel @@ -21,7 +20,8 @@ class ChartIndicatorsViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -43,33 +43,33 @@ class ChartIndicatorsViewController: ThemeViewController { tableView.separatorStyle = .none viewModel.$isLocked - .receive(on: DispatchQueue.main) - .sink { [weak self] isLocked in - self?.isLocked = isLocked - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] isLocked in + self?.isLocked = isLocked + } + .store(in: &cancellables) viewModel.$viewItems - .receive(on: DispatchQueue.main) - .sink { [weak self] viewItems in - self?.viewItems = viewItems - self?.tableView.reload() - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] viewItems in + self?.viewItems = viewItems + self?.tableView.reload() + } + .store(in: &cancellables) viewModel.openSettingsPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] indicator in - self?.openSettings(indicator: indicator) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] indicator in + self?.openSettings(indicator: indicator) + } + .store(in: &cancellables) isLocked = viewModel.isLocked viewItems = viewModel.viewItems tableView.buildSections() } - deinit { // on any dismiss we need to save user indicators + deinit { // on any dismiss we need to save user indicators viewModel.saveIndicators() } @@ -84,10 +84,11 @@ class ChartIndicatorsViewController: ThemeViewController { private func openSettings(indicator: ChartIndicator) { guard let viewController = ChartIndicatorSettingsModule.viewController( - indicator: indicator, - onComplete: { [weak self] indicator in - self?.viewModel.update(indicator: indicator) - }) else { + indicator: indicator, + onComplete: { [weak self] indicator in + self?.viewModel.update(indicator: indicator) + } + ) else { return } @@ -98,11 +99,9 @@ class ChartIndicatorsViewController: ThemeViewController { let viewController = SubscriptionInfoViewController() present(ThemeNavigationController(rootViewController: viewController), animated: true) } - } extension ChartIndicatorsViewController { - private func indicatorRow(viewItem: ChartIndicatorsViewModel.IndicatorViewItem, rowInfo: RowInfo) -> RowProtocol { let isLocked = isLocked let elements: [CellBuilderNew.CellElement] = [ @@ -119,42 +118,37 @@ extension ChartIndicatorsViewController { self?.viewModel.onToggle(viewItem: viewItem, $0) } } - } + }, ] return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: tableView, - id: viewItem.name, - hash: viewItem.name + viewItem.enabled.description, - height: .heightCell48, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) - }, - action: { [weak self] in self?.viewModel.onEdit(viewItem: viewItem) } + rootElement: .hStack(elements), + tableView: tableView, + id: viewItem.name, + hash: viewItem.name + viewItem.enabled.description, + height: .heightCell48, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + }, + action: { [weak self] in self?.viewModel.onEdit(viewItem: viewItem) } ) - } - private func section(viewItem: ChartIndicatorsViewModel.ViewItem) -> SectionProtocol { Section( - id: viewItem.category, - headerState: tableView.sectionHeader(text: viewItem.category), - footerState: .margin(height: .margin24), - rows: viewItem.indicators.enumerated().map { index, item in - indicatorRow(viewItem: item, rowInfo: RowInfo(index: index, count: viewItem.indicators.count)) - } + id: viewItem.category, + headerState: tableView.sectionHeader(text: viewItem.category), + footerState: .margin(height: .margin24), + rows: viewItem.indicators.enumerated().map { index, item in + indicatorRow(viewItem: item, rowInfo: RowInfo(index: index, count: viewItem.indicators.count)) + } ) } - } extension ChartIndicatorsViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { viewItems.map { section(viewItem: $0) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewModel.swift index 2f47a3dbc9..00fef0ee66 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Main/ChartIndicatorsViewModel.swift @@ -1,7 +1,7 @@ -import Combine -import UIKit import Chart +import Combine import MarketKit +import UIKit class ChartIndicatorsViewModel { private let service: ChartIndicatorsService @@ -16,12 +16,12 @@ class ChartIndicatorsViewModel { self.service = service service.$isLocked - .sink { [weak self] in self?.isLocked = $0 } - .store(in: &cancellables) + .sink { [weak self] in self?.isLocked = $0 } + .store(in: &cancellables) service.$items - .sink { [weak self] in self?.sync(items: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(items: $0) } + .store(in: &cancellables) isLocked = service.isLocked sync(items: service.items) @@ -43,26 +43,24 @@ class ChartIndicatorsViewModel { // 1c calculate viewItems for display let indicatorViewItems = items.map { IndicatorViewItem( - id: $0.indicator.id, - index: $0.indicator.index, - name: category.name(id: $0.indicator.id, index: $0.indicator.index), - image: category.image(index: $0.indicator.index), - enabled: $0.indicator.enabled + id: $0.indicator.id, + index: $0.indicator.index, + name: category.name(id: $0.indicator.id, index: $0.indicator.index), + image: category.image(index: $0.indicator.index), + enabled: $0.indicator.enabled ) } return ViewItem( - category: category.title, - indicators: indicatorViewItems, - insufficientData: insufficientData + category: category.title, + indicators: indicatorViewItems, + insufficientData: insufficientData ) } } - } extension ChartIndicatorsViewModel { - var openSettingsPublisher: AnyPublisher { openSettingsSubject.eraseToAnyPublisher() } @@ -85,11 +83,9 @@ extension ChartIndicatorsViewModel { func onToggle(viewItem: ChartIndicatorsViewModel.IndicatorViewItem, _ isOn: Bool) { service.set(enabled: isOn, id: viewItem.id, index: viewItem.index) } - } extension ChartIndicatorsViewModel { - struct IndicatorViewItem { let id: String let index: Int @@ -103,11 +99,9 @@ extension ChartIndicatorsViewModel { let indicators: [IndicatorViewItem] let insufficientData: [String] } - } extension ChartIndicator.Category { - var title: String { switch self { case .movingAverage: return "chart_indicators.moving_averages".localized @@ -131,5 +125,4 @@ extension ChartIndicator.Category { case .oscillator: return id.uppercased() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsModule.swift index aaa09c5ab5..71531dd4db 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsModule.swift @@ -1,13 +1,12 @@ -import UIKit import Chart +import UIKit class ChartIndicatorSettingsModule { - - static func viewController(indicator: ChartIndicator, onComplete: @escaping (ChartIndicator) -> ()) -> UIViewController? { + static func viewController(indicator: ChartIndicator, onComplete: @escaping (ChartIndicator) -> Void) -> UIViewController? { let dataSource: IIndicatorDataSource let defaultIndicator = ChartIndicatorFactory - .defaultIndicators(subscribed: true) - .first { $0.id == indicator.id && $0.index == indicator.index } + .defaultIndicators(subscribed: true) + .first { $0.id == indicator.id && $0.index == indicator.index } switch indicator { case let indicator as MaIndicator: guard let defaultIndicator = defaultIndicator as? MaIndicator else { @@ -32,11 +31,9 @@ class ChartIndicatorSettingsModule { return viewController } - } extension ChartIndicatorSettingsModule { - struct ValueItem { let id: String let value: Any? @@ -95,5 +92,4 @@ extension ChartIndicatorSettingsModule { super.init(id: id) } } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewController.swift index 165c0155cd..cbb09fc606 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewController.swift @@ -1,11 +1,11 @@ -import Combine -import UIKit import Chart +import Combine import ComponentKit import HUD import SectionsTableView import ThemeKit import UIExtensions +import UIKit import UniswapKit class ChartIndicatorSettingsViewController: KeyboardAwareViewController { @@ -27,16 +27,17 @@ class ChartIndicatorSettingsViewController: KeyboardAwareViewController { private var items = [ChartIndicatorSettingsModule.ValueItem]() private var inputSections = [InputIntegerSection]() - private var onComplete: ((ChartIndicator) -> ())? + private var onComplete: ((ChartIndicator) -> Void)? - init(viewModel: ChartIndicatorSettingsViewModel, onComplete: @escaping (ChartIndicator) -> ()) { + init(viewModel: ChartIndicatorSettingsViewModel, onComplete: @escaping (ChartIndicator) -> Void) { self.viewModel = viewModel self.onComplete = onComplete super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -64,54 +65,54 @@ class ChartIndicatorSettingsViewController: KeyboardAwareViewController { applyButton.addTarget(self, action: #selector(onTapDoneButton), for: .touchUpInside) viewModel.itemsUpdatedPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] items in - self?.items = items - self?.tableView.reload(animated: true) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] items in + self?.items = items + self?.tableView.reload(animated: true) + } + .store(in: &cancellables) viewModel.buttonEnabledPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] enabled in - self?.applyButton.isEnabled = enabled - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] enabled in + self?.applyButton.isEnabled = enabled + } + .store(in: &cancellables) viewModel.resetToInitialPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] items in - self?.resetToInitial(items: items) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] items in + self?.resetToInitial(items: items) + } + .store(in: &cancellables) viewModel.resetEnabledPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] enabled in - self?.navigationItem.rightBarButtonItem?.isEnabled = enabled - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] enabled in + self?.navigationItem.rightBarButtonItem?.isEnabled = enabled + } + .store(in: &cancellables) viewModel.cautionPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] cautions in - self?.sync(cautions: cautions) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] cautions in + self?.sync(cautions: cautions) + } + .store(in: &cancellables) viewModel.updateIndicatorPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] indicator in - self?.onApply(indicator: indicator) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] indicator in + self?.onApply(indicator: indicator) + } + .store(in: &cancellables) viewModel.showSubscribeInfoPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.showSubscribeInfo() - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.showSubscribeInfo() + } + .store(in: &cancellables) tableView.buildSections() } @@ -172,50 +173,48 @@ class ChartIndicatorSettingsViewController: KeyboardAwareViewController { self.tableView.endUpdates() } } - } extension ChartIndicatorSettingsViewController { - - private func sectionDescription(id: String, description: String, rowInfo: RowInfo) -> SectionProtocol { + private func sectionDescription(id: String, description: String, rowInfo: RowInfo) -> SectionProtocol { Section( - id: rowInfo.description, - headerState: rowInfo.isFirst ? .margin(height: .margin12) : .margin(height: 0), - footerState: .margin(height: .margin24), - rows: [ - tableView.descriptionRow(id: id, text: description, font: .subhead2, textColor: .gray, ignoreBottomMargin: true) - ] + id: rowInfo.description, + headerState: rowInfo.isFirst ? .margin(height: .margin12) : .margin(height: 0), + footerState: .margin(height: .margin24), + rows: [ + tableView.descriptionRow(id: id, text: description, font: .subhead2, textColor: .gray, ignoreBottomMargin: true), + ] ) } private func sectionList(id: String, hash: String, header: String?, title: String, elements: [ChartIndicatorSettingsModule.ListElement], selected: ChartIndicatorSettingsModule.ListElement) -> SectionProtocol { Section( - id: id, - headerState: header.map { tableView.sectionHeader(text: $0) } ?? .margin(height: 0), - footerState: .margin(height: .margin24), - rows: [ - tableView.universalRow48( - id: id, - title: .body(title), - value: .subhead2(selected.title), - accessoryType: .dropdown, - hash: hash, - autoDeselect: true, - isFirst: true, - isLast: true - ) { [weak self] in - self?.onSelectList(id: id, title: title, elements: elements, selected: selected) - } - ] + id: id, + headerState: header.map { tableView.sectionHeader(text: $0) } ?? .margin(height: 0), + footerState: .margin(height: .margin24), + rows: [ + tableView.universalRow48( + id: id, + title: .body(title), + value: .subhead2(selected.title), + accessoryType: .dropdown, + hash: hash, + autoDeselect: true, + isFirst: true, + isLast: true + ) { [weak self] in + self?.onSelectList(id: id, title: title, elements: elements, selected: selected) + }, + ] ) } private func onSelectList(id: String, title: String, elements: [ChartIndicatorSettingsModule.ListElement], selected: ChartIndicatorSettingsModule.ListElement) { let alertController = AlertRouter.module( - title: title, - viewItems: elements.map { element in - AlertViewItem(text: element.title, selected: element.id == selected.id) - } + title: title, + viewItems: elements.map { element in + AlertViewItem(text: element.title, selected: element.id == selected.id) + } ) { [weak self] index in self?.viewModel.onSelectList(id: id, selected: elements[index]) } @@ -226,11 +225,9 @@ extension ChartIndicatorSettingsViewController { private func onChangeText(id: String, value: String?) { viewModel.onChangeText(id: id, value: value) } - } extension ChartIndicatorSettingsViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() @@ -242,18 +239,19 @@ extension ChartIndicatorSettingsViewController: SectionsDataSource { case let field as ChartIndicatorSettingsModule.ListField: var selected = field.initial if let item = items.first(where: { $0.id == field.id }), - let value = item.value as? ChartIndicatorSettingsModule.ListElement { + let value = item.value as? ChartIndicatorSettingsModule.ListElement + { selected = value } sections.append( - sectionList( - id: field.id, - hash: [field.id, selected.title].joined(separator: "_"), - header: field.header, - title: field.title, - elements: field.elements, - selected: selected - ) + sectionList( + id: field.id, + hash: [field.id, selected.title].joined(separator: "_"), + header: field.header, + title: field.title, + elements: field.elements, + selected: selected + ) ) case let field as ChartIndicatorSettingsModule.InputIntegerField: () var section: InputIntegerSection @@ -268,7 +266,7 @@ extension ChartIndicatorSettingsViewController: SectionsDataSource { inputSections.append(section) } sections.append(section - .section(tableView: tableView, header: field.header) + .section(tableView: tableView, header: field.header) ) default: () } @@ -276,5 +274,4 @@ extension ChartIndicatorSettingsViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewModel.swift index 765e04c7f7..483fffd580 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/ChartIndicatorSettingsViewModel.swift @@ -1,6 +1,6 @@ +import Chart import Combine import Foundation -import Chart class ChartIndicatorSettingsViewModel { private let dataSource: IIndicatorDataSource @@ -42,16 +42,14 @@ class ChartIndicatorSettingsViewModel { switch dataSource.state { case .notChanged: () case .success: applyEnabled = true - case .failed(let cautions): newCautions = cautions + case let .failed(cautions): newCautions = cautions } buttonEnabledSubject.send(applyEnabled) cautionSubject.send(newCautions) } - } extension ChartIndicatorSettingsViewModel { - var title: String { let indicator = dataSource.chartIndicator switch indicator.abstractType { @@ -123,5 +121,4 @@ extension ChartIndicatorSettingsViewModel { updateIndicatorSubject.send(indicator) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/IndicatorDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/IndicatorDataSource.swift index 19d8162da2..c0c0d3e303 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/IndicatorDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/IndicatorDataSource.swift @@ -1,5 +1,5 @@ -import Combine import Chart +import Combine protocol IIndicatorDataSource { var chartIndicator: ChartIndicator { get } @@ -19,12 +19,11 @@ protocol IIndicatorDataSource { var stateUpdatedPublisher: AnyPublisher { get } } -class IndicatorDataSource { - +enum IndicatorDataSource { enum State { - case notChanged - case success(ChartIndicator) - case failed([Caution]) + case notChanged + case success(ChartIndicator) + case failed([Caution]) } struct Caution { @@ -35,11 +34,10 @@ class IndicatorDataSource { static func periodError(id: String, period: Int) -> Caution? { if period < 0 || period > IndicatorCalculator.maximumPeriod { return Caution( - id: id, - error: "chart_indicators.settings.period.error".localized(IndicatorCalculator.maximumPeriod) + id: id, + error: "chart_indicators.settings.period.error".localized(IndicatorCalculator.maximumPeriod) ) } return nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MaIndicatorDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MaIndicatorDataSource.swift index efa7e6ed0b..610927fe33 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MaIndicatorDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MaIndicatorDataSource.swift @@ -1,5 +1,5 @@ -import Combine import Chart +import Combine class MaIndicatorDataSource { private let typeId = "ma-type-list" @@ -17,22 +17,22 @@ class MaIndicatorDataSource { let isChanged = defaultIndicator.period != indicator.period return [ ChartIndicatorSettingsModule.TextField( - id: "title-description", - text: "chart_indicators.settings.ma.description".localized + id: "title-description", + text: "chart_indicators.settings.ma.description".localized ), ChartIndicatorSettingsModule.ListField( - id: typeId, - header: nil, - title: "chart_indicators.settings.ma.type_title".localized, - elements: maTypeElements, - initial: element(of: type) + id: typeId, + header: nil, + title: "chart_indicators.settings.ma.type_title".localized, + elements: maTypeElements, + initial: element(of: type) ), ChartIndicatorSettingsModule.InputIntegerField( - id: periodId, - header: "chart_indicators.settings.ma.period_title".localized, - placeholder: defaultIndicator.period.description, - initial: isChanged ? indicator.period.description : nil - ) + id: periodId, + header: "chart_indicators.settings.ma.period_title".localized, + placeholder: defaultIndicator.period.description, + initial: isChanged ? indicator.period.description : nil + ), ] } @@ -88,21 +88,19 @@ class MaIndicatorDataSource { } state = .success( - MaIndicator( - id: indicator.id, - index: indicator.index, - enabled: indicator.enabled, - period: period, - type: type, - configuration: indicator.configuration - ) + MaIndicator( + id: indicator.id, + index: indicator.index, + enabled: indicator.enabled, + period: period, + type: type, + configuration: indicator.configuration + ) ) } - } extension MaIndicatorDataSource: IIndicatorDataSource { - var chartIndicator: ChartIndicator { indicator } @@ -114,12 +112,12 @@ extension MaIndicatorDataSource: IIndicatorDataSource { var isDefault: Bool { type == defaultIndicator.type && - period == defaultIndicator.period + period == defaultIndicator.period } func set(id: String, value: Any?) { switch id { - case typeId: // change type + case typeId: // change type guard let maType = value as? MaIndicator.MaType else { type = defaultIndicator.type sync() @@ -127,7 +125,7 @@ extension MaIndicatorDataSource: IIndicatorDataSource { } type = maType sync() - case periodId: // change period + case periodId: // change period guard let period = value as? String, let intValue = Int(period) else { period = defaultIndicator.period sync() @@ -149,8 +147,7 @@ extension MaIndicatorDataSource: IIndicatorDataSource { itemsUpdatedSubject.eraseToAnyPublisher() } - var stateUpdatedPublisher: AnyPublisher<(), Never> { + var stateUpdatedPublisher: AnyPublisher { stateUpdatedSubject.eraseToAnyPublisher() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MacdIndicatorDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MacdIndicatorDataSource.swift index 0f76f00304..b0ab199b63 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MacdIndicatorDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/MacdIndicatorDataSource.swift @@ -1,5 +1,5 @@ -import Combine import Chart +import Combine class MacdIndicatorDataSource { private let fastPeriodId = "fast-period-input" @@ -9,26 +9,26 @@ class MacdIndicatorDataSource { var fields: [ChartIndicatorSettingsModule.Field] { [ ChartIndicatorSettingsModule.TextField( - id: "title-description", - text: "chart_indicators.settings.macd.description".localized + id: "title-description", + text: "chart_indicators.settings.macd.description".localized ), ChartIndicatorSettingsModule.InputIntegerField( - id: fastPeriodId, - header: "chart_indicators.settings.macd.fast_period_title".localized, - placeholder: defaultIndicator.fast.description, - initial: defaultIndicator.fast != indicator.fast ? indicator.fast.description : nil + id: fastPeriodId, + header: "chart_indicators.settings.macd.fast_period_title".localized, + placeholder: defaultIndicator.fast.description, + initial: defaultIndicator.fast != indicator.fast ? indicator.fast.description : nil ), ChartIndicatorSettingsModule.InputIntegerField( - id: slowPeriodId, - header: "chart_indicators.settings.macd.slow_period_title".localized, - placeholder: defaultIndicator.slow.description, - initial: defaultIndicator.slow != indicator.slow ? indicator.slow.description : nil + id: slowPeriodId, + header: "chart_indicators.settings.macd.slow_period_title".localized, + placeholder: defaultIndicator.slow.description, + initial: defaultIndicator.slow != indicator.slow ? indicator.slow.description : nil ), ChartIndicatorSettingsModule.InputIntegerField( - id: signalPeriodId, - header: "chart_indicators.settings.macd.signal_period_title".localized, - placeholder: defaultIndicator.signal.description, - initial: defaultIndicator.signal != indicator.signal ? indicator.signal.description : nil + id: signalPeriodId, + header: "chart_indicators.settings.macd.signal_period_title".localized, + placeholder: defaultIndicator.signal.description, + initial: defaultIndicator.signal != indicator.signal ? indicator.signal.description : nil ), ] } @@ -105,41 +105,39 @@ class MacdIndicatorDataSource { } state = .success( - MacdIndicator( - id: indicator.id, - index: indicator.index, - enabled: indicator.enabled, - fast: fastPeriod, - slow: slowPeriod, - signal: signalPeriod, - configuration: indicator.configuration - ) + MacdIndicator( + id: indicator.id, + index: indicator.index, + enabled: indicator.enabled, + fast: fastPeriod, + slow: slowPeriod, + signal: signalPeriod, + configuration: indicator.configuration + ) ) } - } extension MacdIndicatorDataSource: IIndicatorDataSource { - var chartIndicator: ChartIndicator { indicator } var notEdited: Bool { indicator.fast == fastPeriod && - indicator.slow == slowPeriod && - indicator.signal == signalPeriod + indicator.slow == slowPeriod && + indicator.signal == signalPeriod } var isDefault: Bool { fastPeriod == defaultIndicator.fast && - slowPeriod == defaultIndicator.slow && - signalPeriod == defaultIndicator.signal + slowPeriod == defaultIndicator.slow && + signalPeriod == defaultIndicator.signal } func set(id: String, value: Any?) { switch id { - case fastPeriodId: // change period + case fastPeriodId: // change period guard let period = value as? String, let intValue = Int(period) else { fastPeriod = defaultIndicator.fast sync() @@ -147,7 +145,7 @@ extension MacdIndicatorDataSource: IIndicatorDataSource { } fastPeriod = intValue sync() - case slowPeriodId: // change period + case slowPeriodId: // change period guard let period = value as? String, let intValue = Int(period) else { slowPeriod = defaultIndicator.slow sync() @@ -155,7 +153,7 @@ extension MacdIndicatorDataSource: IIndicatorDataSource { } slowPeriod = intValue sync() - case signalPeriodId: // change period + case signalPeriodId: // change period guard let period = value as? String, let intValue = Int(period) else { signalPeriod = defaultIndicator.signal sync() @@ -178,8 +176,7 @@ extension MacdIndicatorDataSource: IIndicatorDataSource { itemsUpdatedSubject.eraseToAnyPublisher() } - var stateUpdatedPublisher: AnyPublisher<(), Never> { + var stateUpdatedPublisher: AnyPublisher { stateUpdatedSubject.eraseToAnyPublisher() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/RsiIndicatorDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/RsiIndicatorDataSource.swift index 2f99a0f5f9..6f1d4393fb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/RsiIndicatorDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/DataSources/RsiIndicatorDataSource.swift @@ -1,5 +1,5 @@ -import Combine import Chart +import Combine class RsiIndicatorDataSource { private let periodId = "rsi-period-input" @@ -8,24 +8,24 @@ class RsiIndicatorDataSource { let isChanged = defaultIndicator.period != indicator.period return [ ChartIndicatorSettingsModule.TextField( - id: "title-description", - text: "chart_indicators.settings.rsi.description".localized + id: "title-description", + text: "chart_indicators.settings.rsi.description".localized ), ChartIndicatorSettingsModule.InputIntegerField( - id: periodId, - header: "chart_indicators.settings.rsi.period_title".localized, - placeholder: defaultIndicator.period.description, - initial: isChanged ? indicator.period.description : nil - ) + id: periodId, + header: "chart_indicators.settings.rsi.period_title".localized, + placeholder: defaultIndicator.period.description, + initial: isChanged ? indicator.period.description : nil + ), ] } var currentItems: [ChartIndicatorSettingsModule.ValueItem] { - [ .init(id: periodId, value: period) ] + [.init(id: periodId, value: period)] } var initialItems: [ChartIndicatorSettingsModule.ValueItem] { - [ .init(id: periodId, value: nil) ] + [.init(id: periodId, value: nil)] } private let itemsUpdatedSubject = PassthroughSubject() @@ -63,20 +63,18 @@ class RsiIndicatorDataSource { } state = .success( - RsiIndicator( - id: indicator.id, - index: indicator.index, - enabled: indicator.enabled, - period: period, - configuration: indicator.configuration - ) + RsiIndicator( + id: indicator.id, + index: indicator.index, + enabled: indicator.enabled, + period: period, + configuration: indicator.configuration + ) ) } - } extension RsiIndicatorDataSource: IIndicatorDataSource { - var chartIndicator: ChartIndicator { indicator } @@ -91,7 +89,7 @@ extension RsiIndicatorDataSource: IIndicatorDataSource { func set(id: String, value: Any?) { switch id { - case periodId: // change period + case periodId: // change period guard let period = value as? String, let intValue = Int(period) else { period = defaultIndicator.period sync() @@ -112,8 +110,7 @@ extension RsiIndicatorDataSource: IIndicatorDataSource { itemsUpdatedSubject.eraseToAnyPublisher() } - var stateUpdatedPublisher: AnyPublisher<(), Never> { + var stateUpdatedPublisher: AnyPublisher { stateUpdatedSubject.eraseToAnyPublisher() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/InputIntegerSection.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/InputIntegerSection.swift index d3fb5473b8..00530d89c7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/InputIntegerSection.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Indicators/Settings/InputIntegerSection.swift @@ -1,5 +1,5 @@ -import UIKit import SectionsTableView +import UIKit class InputIntegerSection { private let inputCell = ShortcutInputCell() @@ -7,8 +7,8 @@ class InputIntegerSection { let id: String - var onChangeText: ((String?) -> ())? - var onReload: (() -> ())? + var onChangeText: ((String?) -> Void)? + var onReload: (() -> Void)? init(id: String, placeholder: String?, initialValue: String?) { self.id = id @@ -29,11 +29,9 @@ class InputIntegerSection { } return true } - } extension InputIntegerSection { - func set(caution: Caution?) { inputCautionCell.set(caution: caution) } @@ -49,20 +47,19 @@ extension InputIntegerSection { footerState: .margin(height: .margin24), rows: [ StaticRow( - cell: inputCell, - id: id + "_input", - dynamicHeight: { [weak self] width in - self?.inputCell.height(containerWidth: width) ?? 0 - } + cell: inputCell, + id: id + "_input", + dynamicHeight: { [weak self] width in + self?.inputCell.height(containerWidth: width) ?? 0 + } ), StaticRow( - cell: inputCautionCell, - id: id + "_caution", - dynamicHeight: { [weak self] width in - self?.inputCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + cell: inputCautionCell, + id: id + "_caution", + dynamicHeight: { [weak self] width in + self?.inputCautionCell.height(containerWidth: width) ?? 0 + } + ), + ]) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankHeaderView.swift index 96386b28b5..ec51017cf3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankHeaderView.swift @@ -1,10 +1,10 @@ -import UIKit -import UIExtensions -import ThemeKit -import SnapKit import ComponentKit -import RxSwift import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIExtensions +import UIKit class CoinRankHeaderView: UITableViewHeaderFooterView { static let height: CGFloat = .heightSingleLineCell @@ -61,7 +61,8 @@ class CoinRankHeaderView: UITableViewHeaderFooterView { subscribe(disposeBag, viewModel.sortDirectionDriver) { [weak self] in self?.syncSortButton(ascending: $0) } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -72,5 +73,4 @@ class CoinRankHeaderView: UITableViewHeaderFooterView { private func syncSortButton(ascending: Bool) { sortButton.set(image: UIImage(named: ascending ? "arrow_medium_2_up_20" : "arrow_medium_2_down_20")) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankModule.swift index bc85b742fe..df17360343 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankModule.swift @@ -1,13 +1,12 @@ -import UIKit import ThemeKit +import UIKit struct CoinRankModule { - static func viewController(type: RankType) -> UIViewController { let service = CoinRankService( - type: type, - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager + type: type, + marketKit: App.shared.marketKit, + currencyManager: App.shared.currencyManager ) let viewModel = CoinRankViewModel(service: service) @@ -15,11 +14,9 @@ struct CoinRankModule { return ThemeNavigationController(rootViewController: viewController) } - } extension CoinRankModule { - enum RankType { case cexVolume case dexVolume @@ -30,5 +27,4 @@ extension CoinRankModule { case fee case revenue } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankService.swift index 4de3e9038e..6ed426b1f2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankService.swift @@ -1,6 +1,6 @@ import Foundation -import MarketKit import HsExtensions +import MarketKit class CoinRankService { let type: CoinRankModule.RankType @@ -90,13 +90,13 @@ class CoinRankService { let resolvedValue: Decimal? switch internalItem.value { - case .multi(let value): + case let .multi(value): switch timePeriod { case .day1: resolvedValue = value.value1d case .week1: resolvedValue = value.value7d default: resolvedValue = value.value30d } - case .single(let value): + case let .single(value): resolvedValue = value.value } @@ -116,19 +116,15 @@ class CoinRankService { state = .loaded(items: sortedIndexedItems, reorder: reorder) } - } extension CoinRankService { - var currency: Currency { currencyManager.baseCurrency } - } extension CoinRankService { - private struct InternalItem { let coin: Coin let value: Value @@ -140,8 +136,8 @@ extension CoinRankService { var coinUid: String { switch self { - case .multi(let value): return value.uid - case .single(let value): return value.uid + case let .multi(value): return value.uid + case let .single(value): return value.uid } } } @@ -162,5 +158,4 @@ extension CoinRankService { let coin: Coin let value: Decimal } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewModel.swift index d877bb9ecd..2e097479b8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewModel.swift @@ -1,9 +1,9 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import RxCocoa +import Foundation import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinRankViewModel { private let timePeriods: [HsTimePeriod] = [.day1, .week1, .month1] @@ -15,15 +15,15 @@ class CoinRankViewModel { private let loadingRelay = BehaviorRelay(value: false) private let syncErrorRelay = BehaviorRelay(value: false) private let sortDirectionRelay: BehaviorRelay - private let scrollToTopRelay = PublishRelay<()>() + private let scrollToTopRelay = PublishRelay() init(service: CoinRankService) { self.service = service sortDirectionRelay = BehaviorRelay(value: service.sortDirectionAscending) service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } @@ -34,7 +34,7 @@ class CoinRankViewModel { viewItemsRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .loaded(let items, let reorder): + case let .loaded(items, reorder): viewItemsRelay.accept(viewItems(items: items)) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -56,14 +56,14 @@ class CoinRankViewModel { } } - private func viewItem(index: Int, item: CoinRankService.IndexedItem, currency: Currency) -> ViewItem { + private func viewItem(index _: Int, item: CoinRankService.IndexedItem, currency: Currency) -> ViewItem { ViewItem( - uid: item.coin.uid, - rank: "\(item.index)", - imageUrl: item.coin.imageUrl, - code: item.coin.code, - name: item.coin.name, - value: formatted(value: item.value, currency: currency) + uid: item.coin.uid, + rank: "\(item.index)", + imageUrl: item.coin.imageUrl, + code: item.coin.code, + name: item.coin.name, + value: formatted(value: item.value, currency: currency) ) } @@ -75,11 +75,9 @@ class CoinRankViewModel { return ValueFormatter.instance.formatShort(value: value) } } - } extension CoinRankViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -92,7 +90,7 @@ extension CoinRankViewModel { syncErrorRelay.asDriver() } - var scrollToTopSignal: Signal<()> { + var scrollToTopSignal: Signal { scrollToTopRelay.asSignal() } @@ -146,7 +144,7 @@ extension CoinRankViewModel { var selectorItems: [String]? { switch service.type { - case .cexVolume, .dexVolume, .address, .txCount, .fee, .revenue: return timePeriods.map { $0.title } + case .cexVolume, .dexVolume, .address, .txCount, .fee, .revenue: return timePeriods.map(\.title) case .dexLiquidity, .holders: return nil } } @@ -162,11 +160,9 @@ extension CoinRankViewModel { func onTapRetry() { service.sync() } - } extension CoinRankViewModel { - struct ViewItem { let uid: String let rank: String @@ -175,5 +171,4 @@ extension CoinRankViewModel { let name: String let value: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsModule.swift index 11a4d8efa1..30a287ef3e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsModule.swift @@ -1,9 +1,7 @@ -struct CoinReportsModule { - +enum CoinReportsModule { static func viewController(coinUid: String) -> CoinReportsViewController { let service = CoinReportsService(coinUid: coinUid, marketKit: App.shared.marketKit) let viewModel = CoinReportsViewModel(service: service) return CoinReportsViewController(viewModel: viewModel, urlManager: UrlManager(inApp: true)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsService.swift index b9708bed83..d1a8911fcb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift class CoinReportsService { private let coinUid: String @@ -38,11 +38,9 @@ class CoinReportsService { } }.store(in: &tasks) } - } extension CoinReportsService { - var stateObservable: Observable> { stateRelay.asObservable() } @@ -50,5 +48,4 @@ extension CoinReportsService { func refresh() { fetch() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewController.swift index 6444be649b..be18d86b5a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import RxSwift -import ThemeKit -import SectionsTableView import ComponentKit import HUD +import RxSwift +import SectionsTableView +import ThemeKit +import UIKit class CoinReportsViewController: ThemeViewController { private let viewModel: CoinReportsViewModel @@ -23,7 +23,8 @@ class CoinReportsViewController: ThemeViewController { super.init() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -81,43 +82,41 @@ class CoinReportsViewController: ThemeViewController { tableView.reload() } - } extension CoinReportsViewController: SectionsDataSource { - private func row(viewItem: CoinReportsViewModel.ViewItem) -> RowProtocol { Row( - id: viewItem.title, - height: PostCell.height, - autoDeselect: true, - bind: { cell, _ in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - cell.bind( - header: viewItem.author, - title: viewItem.title, - body: viewItem.body, - time: viewItem.date - ) - }, - action: { [weak self] _ in - self?.urlManager.open(url: viewItem.url, from: self) - } + id: viewItem.title, + height: PostCell.height, + autoDeselect: true, + bind: { cell, _ in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + cell.bind( + header: viewItem.author, + title: viewItem.title, + body: viewItem.body, + time: viewItem.date + ) + }, + action: { [weak self] _ in + self?.urlManager.open(url: viewItem.url, from: self) + } ) } func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let viewItems = viewItems { + if let viewItems { for (index, viewItem) in viewItems.enumerated() { let section = Section( - id: "report\(index)", - headerState: .margin(height: .margin12), - footerState: .margin(height: index == viewItems.count - 1 ? .margin32 : 0), - rows: [ - row(viewItem: viewItem) - ] + id: "report\(index)", + headerState: .margin(height: .margin12), + footerState: .margin(height: index == viewItems.count - 1 ? .margin32 : 0), + rows: [ + row(viewItem: viewItem), + ] ) sections.append(section) @@ -126,5 +125,4 @@ extension CoinReportsViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewModel.swift index ded00ee932..be14eb1d65 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Reports/CoinReportsViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinReportsViewModel { private let service: CoinReportsService @@ -25,7 +25,7 @@ class CoinReportsViewModel { viewItemsRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .completed(let reports): + case let .completed(reports): viewItemsRelay.accept(reports.map { viewItem(report: $0) }) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -38,18 +38,16 @@ class CoinReportsViewModel { private func viewItem(report: CoinReport) -> ViewItem { ViewItem( - author: report.author, - title: report.title, - body: report.body, - date: DateHelper.instance.formatMonthYear(from: report.date), - url: report.url + author: report.author, + title: report.title, + body: report.body, + date: DateHelper.instance.formatMonthYear(from: report.date), + url: report.url ) } - } extension CoinReportsViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -65,11 +63,9 @@ extension CoinReportsViewModel { func onTapRetry() { service.refresh() } - } extension CoinReportsViewModel { - struct ViewItem { let author: String let title: String @@ -77,5 +73,4 @@ extension CoinReportsViewModel { let date: String let url: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesModule.swift index b2a77a3bea..a007d2f026 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesModule.swift @@ -1,12 +1,10 @@ -import UIKit import MarketKit +import UIKit struct CoinTreasuriesModule { - static func viewController(coin: Coin) -> UIViewController { let service = CoinTreasuriesService(coin: coin, marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager) let viewModel = CoinTreasuriesViewModel(service: service) return CoinTreasuriesViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesService.swift index 9b3a13e2c5..5381f3c1af 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift class CoinTreasuriesService { private let coin: Coin @@ -50,22 +50,22 @@ class CoinTreasuriesService { switch internalState { case .loading: state = .loading - case .completed(let treasuries): + case let .completed(treasuries): let treasuries = treasuries - .filter { - switch typeFilter { - case .all: return true - case .public: return $0.type == .public - case .private: return $0.type == .private - case .etf: return $0.type == .etf - } - } - .sorted { lhsTreasury, rhsTreasury in - sortDirectionAscending ? lhsTreasury.amount < rhsTreasury.amount : lhsTreasury.amount > rhsTreasury.amount + .filter { + switch typeFilter { + case .all: return true + case .public: return $0.type == .public + case .private: return $0.type == .private + case .etf: return $0.type == .etf } + } + .sorted { lhsTreasury, rhsTreasury in + sortDirectionAscending ? lhsTreasury.amount < rhsTreasury.amount : lhsTreasury.amount > rhsTreasury.amount + } state = .loaded(treasuries: treasuries, reorder: reorder) - case .failed(let error): + case let .failed(error): state = .failed(error: error) } } @@ -79,7 +79,7 @@ class CoinTreasuriesService { Task { [weak self, marketKit, coin, currencyManager] in do { - let treasuries = try await marketKit.treasuries(coinUid: coin.uid, currencyCode: currencyManager.baseCurrency.code) + let treasuries = try await marketKit.treasuries(coinUid: coin.uid, currencyCode: currencyManager.baseCurrency.code) self?.internalState = .completed(treasuries) } catch { self?.internalState = .failed(error) @@ -94,11 +94,9 @@ class CoinTreasuriesService { syncState(reorder: reorder) } - } extension CoinTreasuriesService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -122,11 +120,9 @@ extension CoinTreasuriesService { func refresh() { syncTreasuries() } - } extension CoinTreasuriesService { - enum State { case loading case loaded(treasuries: [CoinTreasury], reorder: Bool) @@ -139,5 +135,4 @@ extension CoinTreasuriesService { case `private` case etf } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewController.swift index 3ac777b9fe..8a5c89c6fe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewController.swift @@ -1,12 +1,12 @@ +import ComponentKit import Foundation -import UIKit -import RxSwift +import HUD import RxCocoa +import RxSwift +import SectionsTableView import SnapKit import ThemeKit -import SectionsTableView -import ComponentKit -import HUD +import UIKit class CoinTreasuriesViewController: ThemeViewController { private let viewModel: CoinTreasuriesViewModel @@ -28,7 +28,8 @@ class CoinTreasuriesViewController: ThemeViewController { headerView.viewController = self } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -93,90 +94,87 @@ class CoinTreasuriesViewController: ThemeViewController { private func scrollToTop() { tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .bottom, animated: true) } - } extension CoinTreasuriesViewController: SectionsDataSource { - private func row(viewItem: CoinTreasuriesViewModel.ViewItem, index: Int, isLast: Bool) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .image32 { component in - component.setImage(urlString: viewItem.logoUrl, placeholder: UIImage(named: "placeholder_circle_32")) - }, - .vStackCentered([ - .hStack([ - .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = viewItem.fund - }, - .text { component in - component.font = .body - component.textColor = .themeLeah - component.textAlignment = .right - component.setContentCompressionResistancePriority(.required, for: .horizontal) - component.text = viewItem.amount - } - ]), - .margin(1), - .hStack([ - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = viewItem.country - }, - .text { component in - component.setContentCompressionResistancePriority(.required, for: .horizontal) - component.setContentHuggingPriority(.required, for: .horizontal) - component.textAlignment = .right - component.font = .subhead2 - component.textColor = .themeJacob - component.text = viewItem.amountInCurrency - } - ]) - ]) + rootElement: .hStack([ + .image32 { component in + component.setImage(urlString: viewItem.logoUrl, placeholder: UIImage(named: "placeholder_circle_32")) + }, + .vStackCentered([ + .hStack([ + .text { component in + component.font = .body + component.textColor = .themeLeah + component.text = viewItem.fund + }, + .text { component in + component.font = .body + component.textColor = .themeLeah + component.textAlignment = .right + component.setContentCompressionResistancePriority(.required, for: .horizontal) + component.text = viewItem.amount + }, + ]), + .margin(1), + .hStack([ + .text { component in + component.font = .subhead2 + component.textColor = .themeGray + component.text = viewItem.country + }, + .text { component in + component.setContentCompressionResistancePriority(.required, for: .horizontal) + component.setContentHuggingPriority(.required, for: .horizontal) + component.textAlignment = .right + component.font = .subhead2 + component.textColor = .themeJacob + component.text = viewItem.amountInCurrency + }, + ]), ]), - tableView: tableView, - id: "treasury-\(index)", - height: .heightDoubleLineCell, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - } + ]), + tableView: tableView, + id: "treasury-\(index)", + height: .heightDoubleLineCell, + bind: { cell in + cell.set(backgroundStyle: .transparent, isLast: isLast) + } ) } private func poweredBySection(text: String) -> SectionProtocol { Section( - id: "powered-by", - rows: [ - Row( - id: "powered-by", - dynamicHeight: { containerWidth in - BrandFooterCell.height(containerWidth: containerWidth, title: text) - }, - bind: { cell, _ in - cell.title = text - } - ) - ] + id: "powered-by", + rows: [ + Row( + id: "powered-by", + dynamicHeight: { containerWidth in + BrandFooterCell.height(containerWidth: containerWidth, title: text) + }, + bind: { cell, _ in + cell.title = text + } + ), + ] ) } func buildSections() -> [SectionProtocol] { - guard let viewItems = viewItems else { + guard let viewItems else { return [] } return [ Section( - id: "treasuries", - headerState: .static(view: headerView, height: .heightSingleLineCell), - footerState: .marginColor(height: .margin32, color: .clear), - rows: viewItems.enumerated().map { row(viewItem: $1, index: $0, isLast: $0 == viewItems.count - 1) } + id: "treasuries", + headerState: .static(view: headerView, height: .heightSingleLineCell), + footerState: .marginColor(height: .margin32, color: .clear), + rows: viewItems.enumerated().map { row(viewItem: $1, index: $0, isLast: $0 == viewItems.count - 1) } ), - poweredBySection(text: "Powered by Bitcointreasuries.net") + poweredBySection(text: "Powered by Bitcointreasuries.net"), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewModel.swift index 2dca7f7abf..72111a9955 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Treasuries/CoinTreasuriesViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class CoinTreasuriesViewModel { private let service: CoinTreasuriesService @@ -10,7 +10,7 @@ class CoinTreasuriesViewModel { private let viewItemsRelay = BehaviorRelay<[ViewItem]?>(value: nil) private let loadingRelay = BehaviorRelay(value: false) private let syncErrorRelay = BehaviorRelay(value: false) - private let scrollToTopRelay = PublishRelay<()>() + private let scrollToTopRelay = PublishRelay() private let dropdownValueRelay = BehaviorRelay(value: "") private let sortDirectionAscendingRelay = BehaviorRelay(value: false) @@ -33,7 +33,7 @@ class CoinTreasuriesViewModel { viewItemsRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .loaded(let treasuries, let reorder): + case let .loaded(treasuries, reorder): viewItemsRelay.accept(treasuries.map { viewItem(treasury: $0) }) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -58,11 +58,11 @@ class CoinTreasuriesViewModel { private func viewItem(treasury: CoinTreasury) -> ViewItem { ViewItem( - logoUrl: treasury.fundLogoUrl, - fund: treasury.fund, - country: treasury.country, - amount: ValueFormatter.instance.formatShort(value: treasury.amount, decimalCount: 8, symbol: service.coinCode) ?? "---", - amountInCurrency: ValueFormatter.instance.formatShort(currency: service.currency, value: treasury.amountInCurrency) ?? "---" + logoUrl: treasury.fundLogoUrl, + fund: treasury.fund, + country: treasury.country, + amount: ValueFormatter.instance.formatShort(value: treasury.amount, decimalCount: 8, symbol: service.coinCode) ?? "---", + amountInCurrency: ValueFormatter.instance.formatShort(currency: service.currency, value: treasury.amountInCurrency) ?? "---" ) } @@ -77,7 +77,6 @@ class CoinTreasuriesViewModel { } extension CoinTreasuriesViewModel: IDropdownSortHeaderViewModel { - var dropdownTitle: String { "coin_analytics.treasuries.filters".localized } @@ -103,11 +102,9 @@ extension CoinTreasuriesViewModel: IDropdownSortHeaderViewModel { func onToggleSortDirection() { service.sortDirectionAscending = !service.sortDirectionAscending } - } extension CoinTreasuriesViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -120,18 +117,16 @@ extension CoinTreasuriesViewModel { syncErrorRelay.asDriver() } - var scrollToTopSignal: Signal<()> { + var scrollToTopSignal: Signal { scrollToTopRelay.asSignal() } func onTapRetry() { service.refresh() } - } extension CoinTreasuriesViewModel { - struct ViewItem { let logoUrl: String let fund: String @@ -139,5 +134,4 @@ extension CoinTreasuriesViewModel { let amount: String let amountInCurrency: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectModule.swift index 89bc14c2da..f3372bdf39 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectModule.swift @@ -1,24 +1,22 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit protocol ICoinSelectDelegate: AnyObject { func didSelect(token: Token) } -struct CoinSelectModule { - +enum CoinSelectModule { static func viewController(dex: SwapModule.Dex, delegate: ICoinSelectDelegate) -> UIViewController { let service = CoinSelectService( - dex: dex, - marketKit: App.shared.marketKit, - walletManager: App.shared.walletManager, - adapterManager: App.shared.adapterManager, - currencyManager: App.shared.currencyManager + dex: dex, + marketKit: App.shared.marketKit, + walletManager: App.shared.walletManager, + adapterManager: App.shared.adapterManager, + currencyManager: App.shared.currencyManager ) let viewModel = CoinSelectViewModel(service: service) return CoinSelectViewController(viewModel: viewModel, delegate: delegate) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectService.swift index 5e1f11fb4b..a9704c50fa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class CoinSelectService { private let dex: SwapModule.Dex @@ -129,11 +129,9 @@ class CoinSelectService { return lhsItem.token.coin.name.lowercased() < rhsItem.token.coin.name.lowercased() } } - } extension CoinSelectService { - var itemsObservable: Observable<[Item]> { itemsRelay.asObservable() } @@ -147,15 +145,12 @@ extension CoinSelectService { syncItems() } - } extension CoinSelectService { - struct Item { let token: Token let balance: Decimal? let rate: Decimal? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewController.swift index 3d1d09c18a..43ab82c4ba 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewController.swift @@ -1,12 +1,12 @@ +import Alamofire import Combine -import UIKit +import ComponentKit +import MarketKit +import RxSwift import SectionsTableView import SnapKit import ThemeKit -import RxSwift -import MarketKit -import ComponentKit -import Alamofire +import UIKit class CoinSelectViewController: ThemeSearchViewController { private let viewModel: CoinSelectViewModel @@ -24,7 +24,8 @@ class CoinSelectViewController: ThemeSearchViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -48,9 +49,9 @@ class CoinSelectViewController: ThemeSearchViewController { subscribe(disposeBag, viewModel.viewItemsDriver) { [weak self] in self?.handle(viewItems: $0) } $filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.viewModel.apply(filter: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.viewModel.apply(filter: $0) } + .store(in: &cancellables) } @objc func onTapClose() { @@ -67,72 +68,69 @@ class CoinSelectViewController: ThemeSearchViewController { tableView.reload() } - } extension CoinSelectViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "coins", - headerState: .margin(height: .margin3x), - footerState: .margin(height: .margin8x), - rows: viewItems.enumerated().map { index, viewItem in - let isLast = index == viewItems.count - 1 - - return CellBuilderNew.row( - rootElement: .hStack([ - .image32 { component in - component.setImage(urlString: viewItem.token.coin.imageUrl, placeholder: UIImage(named: viewItem.token.placeholderImageName)) + id: "coins", + headerState: .margin(height: .margin3x), + footerState: .margin(height: .margin8x), + rows: viewItems.enumerated().map { index, viewItem in + let isLast = index == viewItems.count - 1 + + return CellBuilderNew.row( + rootElement: .hStack([ + .image32 { component in + component.setImage(urlString: viewItem.token.coin.imageUrl, placeholder: UIImage(named: viewItem.token.placeholderImageName)) + }, + .vStackCentered([ + .hStack([ + .text { component in + component.font = .body + component.textColor = .themeLeah + component.text = viewItem.token.coin.code + }, + .text { component in + component.font = .body + component.textColor = .themeLeah + component.textAlignment = .right + component.setContentCompressionResistancePriority(.required, for: .horizontal) + component.text = viewItem.balance }, - .vStackCentered([ - .hStack([ - .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = viewItem.token.coin.code - }, - .text { component in - component.font = .body - component.textColor = .themeLeah - component.textAlignment = .right - component.setContentCompressionResistancePriority(.required, for: .horizontal) - component.text = viewItem.balance - } - ]), - .margin(3), - .hStack([ - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = viewItem.token.coin.name - }, - .text { component in - component.setContentCompressionResistancePriority(.required, for: .horizontal) - component.setContentHuggingPriority(.required, for: .horizontal) - component.textAlignment = .right - component.font = .subhead2 - component.textColor = .themeGray - component.text = viewItem.fiatBalance - } - ]) - ]) ]), - tableView: tableView, - id: "coin_\(index)", - height: .heightDoubleLineCell, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - }, - action: { [weak self] in - self?.onSelect(token: viewItem.token) - } - ) - } - ) + .margin(3), + .hStack([ + .text { component in + component.font = .subhead2 + component.textColor = .themeGray + component.text = viewItem.token.coin.name + }, + .text { component in + component.setContentCompressionResistancePriority(.required, for: .horizontal) + component.setContentHuggingPriority(.required, for: .horizontal) + component.textAlignment = .right + component.font = .subhead2 + component.textColor = .themeGray + component.text = viewItem.fiatBalance + }, + ]), + ]), + ]), + tableView: tableView, + id: "coin_\(index)", + height: .heightDoubleLineCell, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .transparent, isLast: isLast) + }, + action: { [weak self] in + self?.onSelect(token: viewItem.token) + } + ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewModel.swift index 08c4daef1c..3680e935e9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CoinSelect/CoinSelectViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift class CoinSelectViewModel { private let service: CoinSelectService @@ -20,23 +20,21 @@ class CoinSelectViewModel { private func sync(items: [CoinSelectService.Item]) { let viewItems = items.map { item -> ViewItem in let formatted = item.balance - .flatMap { CoinValue(kind: .token(token: item.token), value: $0) } - .flatMap { ValueFormatter.instance.formatShort(coinValue: $0) } + .flatMap { CoinValue(kind: .token(token: item.token), value: $0) } + .flatMap { ValueFormatter.instance.formatShort(coinValue: $0) } let fiatFormatted = item.rate - .flatMap { rate in item.balance.map { $0 * rate } } - .flatMap { ValueFormatter.instance.formatShort(currency: service.currency, value: $0) } + .flatMap { rate in item.balance.map { $0 * rate } } + .flatMap { ValueFormatter.instance.formatShort(currency: service.currency, value: $0) } return ViewItem(token: item.token, balance: formatted, fiatBalance: fiatFormatted) } viewItemsRelay.accept(viewItems) } - } extension CoinSelectViewModel { - public var viewItemsDriver: Driver<[ViewItem]> { viewItemsRelay.asDriver() } @@ -46,15 +44,12 @@ extension CoinSelectViewModel { self?.service.set(filter: filter?.trimmingCharacters(in: .whitespaces) ?? "") } } - } extension CoinSelectViewModel { - struct ViewItem { let token: Token let balance: String? let fiatBalance: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressModule.swift index ab20e9c5f2..ff0ce7fef4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressModule.swift @@ -1,10 +1,9 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit class ContactBookAddressModule { - - static func viewController(contactUid: String?, existAddresses: [ContactAddress], currentAddress: ContactAddress? = nil, onSaveAddress: @escaping (ContactAddress?) -> ()) -> UIViewController? { + static func viewController(contactUid: String?, existAddresses: [ContactAddress], currentAddress: ContactAddress? = nil, onSaveAddress: @escaping (ContactAddress?) -> Void) -> UIViewController? { let service: ContactBookAddressService let addressService: AddressService if let currentAddress { @@ -15,14 +14,14 @@ class ContactBookAddressModule { service = ContactBookAddressService(marketKit: App.shared.marketKit, addressService: addressService, contactBookManager: App.shared.contactManager, currentContactUid: contactUid, mode: .edit(currentAddress), blockchain: blockchain) } else { let blockchainUids = BlockchainType - .supported - .map { $0.uid } - .filter { uid in - !existAddresses.contains(where: { address in address.blockchainUid == uid }) - } + .supported + .map(\.uid) + .filter { uid in + !existAddresses.contains(where: { address in address.blockchainUid == uid }) + } let allBlockchains = ((try? App.shared.marketKit.blockchains(uids: blockchainUids)) ?? []) - .sorted { $0.type.order < $1.type.order } + .sorted { $0.type.order < $1.type.order } guard let firstBlockchain = allBlockchains.first else { return nil @@ -36,14 +35,11 @@ class ContactBookAddressModule { let controller = ContactBookAddressViewController(viewModel: viewModel, addressViewModel: addressViewModel, onUpdateAddress: onSaveAddress) return ThemeNavigationController(rootViewController: controller) } - } extension ContactBookAddressModule { - enum Mode { case create([ContactAddress]) case edit(ContactAddress) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressService.swift index 4afe7bb032..c3687bc568 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class ContactBookAddressService { private let disposeBag = DisposeBag() @@ -45,15 +45,15 @@ class ContactBookAddressService { self.currentContactUid = currentContactUid self.mode = mode - let blockchainUids = BlockchainType.supported.map { $0.uid } + let blockchainUids = BlockchainType.supported.map(\.uid) let allBlockchains = ((try? marketKit.blockchains(uids: blockchainUids)) ?? []).sorted { $0.type.order < $1.type.order } switch mode { - case .create(let addresses): + case let .create(addresses): let usedBlockchains = addresses.compactMap { try? marketKit.blockchain(uid: $0.blockchainUid) } unusedBlockchains = allBlockchains.filter { !usedBlockchains.contains($0) } initialAddress = nil - case .edit(let address): + case let .edit(address): unusedBlockchains = allBlockchains initialAddress = address } @@ -68,7 +68,6 @@ class ContactBookAddressService { sync() } - private func contact(with address: ContactAddress) -> Contact? { var otherContacts = contactBookManager.all if let contactUid = currentContactUid { @@ -87,7 +86,7 @@ class ContactBookAddressService { state = .loading case .validationError, .fetchError: state = .invalid(ValidationError.invalidAddress) - case .success(let address): + case let .success(address): if let initialAddress, address.raw.lowercased() == initialAddress.address.lowercased() { state = .idle return @@ -95,7 +94,6 @@ class ContactBookAddressService { let address = ContactAddress(blockchainUid: selectedBlockchain.type.uid, address: address.raw) if let contact = contact(with: address) { - let error = ValidationError.duplicate(contact: contact) self.error = error state = .invalid(error) @@ -106,11 +104,9 @@ class ContactBookAddressService { } error = nil } - } extension ContactBookAddressService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -118,11 +114,9 @@ extension ContactBookAddressService { var selectedBlockchainObservable: Observable { selectedBlockchainRelay.asObservable() } - } extension ContactBookAddressService { - enum State { case idle case loading @@ -134,13 +128,10 @@ extension ContactBookAddressService { case invalidAddress case duplicate(contact: Contact) } - } extension ContactBookAddressService: IErrorService { - var errorObservable: Observable { errorRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewController.swift index 8a92b55585..6738eae316 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewController.swift @@ -1,15 +1,15 @@ -import UIKit +import ComponentKit import Foundation -import RxSwift import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit import ThemeKit import UIExtensions +import UIKit class ContactBookAddressViewController: KeyboardAwareViewController { private let viewModel: ContactBookAddressViewModel - private let onUpdateAddress: (ContactAddress?) -> () + private let onUpdateAddress: (ContactAddress?) -> Void private let disposeBag = DisposeBag() private let tableView = SectionsTableView(style: .grouped) @@ -30,7 +30,7 @@ class ContactBookAddressViewController: KeyboardAwareViewController { private var blockchainName: String = "" private var addAddressEnabled: Bool = true - init(viewModel: ContactBookAddressViewModel, addressViewModel: RecipientAddressViewModel, onUpdateAddress: @escaping (ContactAddress?) -> ()) { + init(viewModel: ContactBookAddressViewModel, addressViewModel: RecipientAddressViewModel, onUpdateAddress: @escaping (ContactAddress?) -> Void) { self.viewModel = viewModel recipientCell = RecipientAddressInputCell(viewModel: addressViewModel) recipientCautionCell = RecipientAddressCautionCell(viewModel: addressViewModel) @@ -47,7 +47,8 @@ class ContactBookAddressViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -123,17 +124,17 @@ class ContactBookAddressViewController: KeyboardAwareViewController { @objc private func onCloseConfirmation() { if addressWasChanged { let viewController = BottomSheetModule.viewController( - image: .warning, - title: "alert.warning".localized, - items: [ - .highlightedDescription(text: "contacts.contact.dismiss_changes.description".localized) - ], - buttons: [ - .init(style: .red, title: "contacts.contact.dismiss_changes.discard_changes".localized, actionType: .afterClose) { [ weak self] in - self?.onClose() - }, - .init(style: .transparent, title: "contacts.contact.dismiss_changes.keep_editing".localized) - ] + image: .warning, + title: "alert.warning".localized, + items: [ + .highlightedDescription(text: "contacts.contact.dismiss_changes.description".localized), + ], + buttons: [ + .init(style: .red, title: "contacts.contact.dismiss_changes.discard_changes".localized, actionType: .afterClose) { [weak self] in + self?.onClose() + }, + .init(style: .transparent, title: "contacts.contact.dismiss_changes.keep_editing".localized), + ] ) present(viewController, animated: true) } else { @@ -150,18 +151,18 @@ class ContactBookAddressViewController: KeyboardAwareViewController { private func onTapDeleteAddress() { let viewController = BottomSheetModule.viewController( - image: .warning, - title: "contacts.add_address.delete_alert.title".localized, - items: [ - .highlightedDescription(text: "contacts.add_address.delete_alert.description".localized) - ], - buttons: [ - .init(style: .red, title: "contacts.add_address.delete_alert.delete".localized, actionType: .afterClose) { [ weak self] in - self?.onUpdateAddress(nil) - self?.dismiss(animated: true) - }, - .init(style: .transparent, title: "button.cancel".localized) - ] + image: .warning, + title: "contacts.add_address.delete_alert.title".localized, + items: [ + .highlightedDescription(text: "contacts.add_address.delete_alert.description".localized), + ], + buttons: [ + .init(style: .red, title: "contacts.add_address.delete_alert.delete".localized, actionType: .afterClose) { [weak self] in + self?.onUpdateAddress(nil) + self?.dismiss(animated: true) + }, + .init(style: .transparent, title: "button.cancel".localized), + ] ) present(viewController, animated: true) @@ -169,11 +170,11 @@ class ContactBookAddressViewController: KeyboardAwareViewController { private func onTapBlockchain() { let viewController = SelectorModule.singleSelectorViewController( - title: "contacts.contact.address.blockchains".localized, - viewItems: viewModel.blockchainViewItems, - onSelect: { [weak self] in - self?.viewModel.setBlockchain(index: $0) - } + title: "contacts.contact.address.blockchains".localized, + viewItems: viewModel.blockchainViewItems, + onSelect: { [weak self] in + self?.viewModel.setBlockchain(index: $0) + } ) present(viewController, animated: true) @@ -188,13 +189,12 @@ class ContactBookAddressViewController: KeyboardAwareViewController { autoDeselect: true, isFirst: true, isLast: true, - action: viewModel.existAddress ? nil : { [weak self] in self?.onTapBlockchain() }) + action: viewModel.existAddress ? nil : { [weak self] in self?.onTapBlockchain() } + ) } - } extension ContactBookAddressViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [ Section(id: "actions", @@ -202,52 +202,50 @@ extension ContactBookAddressViewController: SectionsDataSource { footerState: .margin(height: .margin32), rows: [blockchainRow]), Section( - id: "name", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: recipientCell, - id: "name", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "name-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + id: "name", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: recipientCell, + id: "name", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: recipientCautionCell, + id: "name-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), ] if viewModel.existAddress { sections.append( - Section(id: "actions", + Section(id: "actions", footerState: .margin(height: .margin32), rows: [ tableView.universalRow48( - id: "delete_address", - image: .local(UIImage(named: "trash_24")?.withTintColor(.themeLucian)), - title: .body("contacts.contact.address.delete_address".localized, color: .themeLucian), - autoDeselect: true, - isFirst: true, - isLast: true, - action: { [weak self] in - self?.onTapDeleteAddress() - } - ) + id: "delete_address", + image: .local(UIImage(named: "trash_24")?.withTintColor(.themeLucian)), + title: .body("contacts.contact.address.delete_address".localized, color: .themeLucian), + autoDeselect: true, + isFirst: true, + isLast: true, + action: { [weak self] in + self?.onTapDeleteAddress() + } + ), ]) ) } return sections } - } extension ContactBookAddressViewController: IDynamicHeightCellDelegate { - func onChangeHeight() { guard isLoaded else { return @@ -258,5 +256,4 @@ extension ContactBookAddressViewController: IDynamicHeightCellDelegate { self?.tableView.endUpdates() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewModel.swift index 869b63d713..c50afb0a02 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookAddress/ContactBookAddressViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class ContactBookAddressViewModel { private let disposeBag = DisposeBag() @@ -15,6 +15,7 @@ class ContactBookAddressViewModel { viewItemRelay.accept(viewItem) } } + private let blockchainNameRelay = BehaviorRelay(value: "") private let addressCautionRelay = BehaviorRelay(value: nil) private let saveEnabledRelay = BehaviorRelay(value: false) @@ -32,7 +33,7 @@ class ContactBookAddressViewModel { switch state { case .idle, .loading: () - case .valid(let item): + case let .valid(item): saveEnabled = true viewItem = viewItem(item: item) case .invalid: @@ -49,11 +50,9 @@ class ContactBookAddressViewModel { private func viewItem(item: ContactAddress) -> String { item.address } - } extension ContactBookAddressViewModel { - var existAddress: Bool { switch service.mode { case .edit: return true @@ -82,9 +81,9 @@ extension ContactBookAddressViewModel { var blockchainViewItems: [SelectorModule.ViewItem] { service.unusedBlockchains.map { blockchain in SelectorModule.ViewItem( - image: .url(blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), - title: blockchain.name, - selected: service.selectedBlockchain == blockchain + image: .url(blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), + title: blockchain.name, + selected: service.selectedBlockchain == blockchain ) } } @@ -115,7 +114,7 @@ extension ContactBookAddressViewModel { extension ContactBookAddressService.ValidationError: LocalizedError { var errorDescription: String? { switch self { - case .duplicate(let contact): return "contacts.add_address.exist_address".localized(contact.name) + case let .duplicate(contact): return "contacts.add_address.exist_address".localized(contact.name) case .invalidAddress: return nil } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactModule.swift index ca531e8e97..5006a4fcd6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactModule.swift @@ -1,31 +1,30 @@ -import UIKit import ThemeKit +import UIKit class ContactBookContactModule { - - static func viewController(mode: Mode, onUpdateContact: (() -> ())? = nil) -> UIViewController? { + static func viewController(mode: Mode, onUpdateContact: (() -> Void)? = nil) -> UIViewController? { let service: ContactBookContactService switch mode { case .new: service = ContactBookContactService( - contactManager: App.shared.contactManager, - marketKit: App.shared.marketKit, - contact: nil + contactManager: App.shared.contactManager, + marketKit: App.shared.marketKit, + contact: nil ) - case .exist(let uid, let newAddresses): + case let .exist(uid, newAddresses): service = ContactBookContactService( - contactManager: App.shared.contactManager, - marketKit: App.shared.marketKit, - contact: App.shared.contactManager.all?.first(where: { $0.uid == uid }), - newAddresses: newAddresses + contactManager: App.shared.contactManager, + marketKit: App.shared.marketKit, + contact: App.shared.contactManager.all?.first(where: { $0.uid == uid }), + newAddresses: newAddresses ) case let .add(address): service = ContactBookContactService( - contactManager: App.shared.contactManager, - marketKit: App.shared.marketKit, - contact: nil, - newAddresses: [address] + contactManager: App.shared.contactManager, + marketKit: App.shared.marketKit, + contact: nil, + newAddresses: [address] ) } @@ -34,15 +33,12 @@ class ContactBookContactModule { let controller = ContactBookContactViewController(viewModel: viewModel, onUpdateContact: onUpdateContact) return ThemeNavigationController(rootViewController: controller) } - } extension ContactBookContactModule { - enum Mode { case new case exist(String, [ContactAddress]) case add(ContactAddress) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactService.swift index de163729fe..b6f7b23fb2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class ContactBookContactService { private let disposeBag = DisposeBag() @@ -62,15 +62,15 @@ class ContactBookContactService { private func syncAddresses() { let addressItems = addresses.compactMap { address -> AddressItem? in - var edited = true - // check if old address same with new - set edited false - if let oldAddresses = oldContact?.addresses, - let oldAddress = oldAddresses.first(where: { $0.blockchainUid == address.blockchainUid }) { - edited = oldAddress.address != address.address - } - return blockchain(by: address).map { AddressItem(blockchain: $0, address: address.address, edited: edited) } - }.sorted { item, item2 in item.blockchain.type.order < item2.blockchain.type.order } - + var edited = true + // check if old address same with new - set edited false + if let oldAddresses = oldContact?.addresses, + let oldAddress = oldAddresses.first(where: { $0.blockchainUid == address.blockchainUid }) + { + edited = oldAddress.address != address.address + } + return blockchain(by: address).map { AddressItem(blockchain: $0, address: address.address, edited: edited) } + }.sorted { item, item2 in item.blockchain.type.order < item2.blockchain.type.order } addressItemsRelay.accept(addressItems) } @@ -83,20 +83,20 @@ class ContactBookContactService { // check if all blockchains has addresses allBlockchainsUsedRelay.accept( - BlockchainType - .supported - .filter({ type in - !usedBlockchainTypes.contains(type) - }).count == 0 + BlockchainType + .supported + .filter { type in + !usedBlockchainTypes.contains(type) + }.count == 0 ) } private func sync() { // check if name already exist let otherContactNames = contactManager - .all? - .filter { (oldContact?.name ?? "") != $0.name } - .map { $0.name.lowercased() } ?? [] + .all? + .filter { (oldContact?.name ?? "") != $0.name } + .map { $0.name.lowercased() } ?? [] if otherContactNames.contains(contactName.lowercased()) { state = .error(ValidationError.nameExist) @@ -116,11 +116,9 @@ class ContactBookContactService { state = .updated } - } extension ContactBookContactService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -164,11 +162,9 @@ extension ContactBookContactService { } try contactManager.delete(uid) } - } extension ContactBookContactService { - struct AddressItem { let blockchain: Blockchain let address: String @@ -189,5 +185,4 @@ extension ContactBookContactService { enum ValidationError: Error { case nameExist } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewController.swift index 5c3c32382a..cb48ff2a4f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewController.swift @@ -1,15 +1,15 @@ -import UIKit +import ComponentKit import Foundation -import RxSwift import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit import ThemeKit +import UIKit class ContactBookContactViewController: KeyboardAwareViewController { private let disposeBag = DisposeBag() private let viewModel: ContactBookContactViewModel - private let onUpdateContact: (() -> ())? + private let onUpdateContact: (() -> Void)? private let deleteContactHidden: Bool private let tableView = SectionsTableView(style: .grouped) @@ -28,7 +28,7 @@ class ContactBookContactViewController: KeyboardAwareViewController { private var addressViewItems: [ContactBookContactViewModel.AddressViewItem] = [] private var addAddressHidden: Bool = false - init(viewModel: ContactBookContactViewModel, onUpdateContact: (() -> ())? = nil) { + init(viewModel: ContactBookContactViewModel, onUpdateContact: (() -> Void)? = nil) { self.viewModel = viewModel self.onUpdateContact = onUpdateContact deleteContactHidden = !viewModel.editExisting @@ -36,7 +36,8 @@ class ContactBookContactViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -104,17 +105,17 @@ class ContactBookContactViewController: KeyboardAwareViewController { @objc private func onCloseConfirmation() { if contactWasChanged { let viewController = BottomSheetModule.viewController( - image: .warning, - title: "alert.warning".localized, - items: [ - .highlightedDescription(text: "contacts.contact.dismiss_changes.description".localized) - ], - buttons: [ - .init(style: .red, title: "contacts.contact.dismiss_changes.discard_changes".localized, actionType: .afterClose) { [ weak self] in - self?.onClose() - }, - .init(style: .transparent, title: "contacts.contact.dismiss_changes.keep_editing".localized) - ] + image: .warning, + title: "alert.warning".localized, + items: [ + .highlightedDescription(text: "contacts.contact.dismiss_changes.description".localized), + ], + buttons: [ + .init(style: .red, title: "contacts.contact.dismiss_changes.discard_changes".localized, actionType: .afterClose) { [weak self] in + self?.onClose() + }, + .init(style: .transparent, title: "contacts.contact.dismiss_changes.keep_editing".localized), + ] ) present(viewController, animated: true) } else { @@ -135,23 +136,23 @@ class ContactBookContactViewController: KeyboardAwareViewController { onUpdate() } catch { print("Can't update \(error)") - // todo: show error alert! + // TODO: show error alert! } } private func onTapDeleteContact() { let viewController = BottomSheetModule.viewController( - image: .warning, - title: "contacts.contact.delete_alert.title".localized, - items: [ - .highlightedDescription(text: "contacts.contact.delete_alert.description".localized) - ], - buttons: [ - .init(style: .red, title: "contacts.contact.delete_alert.delete".localized, actionType: .afterClose) { [ weak self] in - self?.acceptDeleteContact() - }, - .init(style: .transparent, title: "button.cancel".localized) - ] + image: .warning, + title: "contacts.contact.delete_alert.title".localized, + items: [ + .highlightedDescription(text: "contacts.contact.delete_alert.description".localized), + ], + buttons: [ + .init(style: .red, title: "contacts.contact.delete_alert.delete".localized, actionType: .afterClose) { [weak self] in + self?.acceptDeleteContact() + }, + .init(style: .transparent, title: "button.cancel".localized), + ] ) present(viewController, animated: true) @@ -163,12 +164,12 @@ class ContactBookContactViewController: KeyboardAwareViewController { onUpdate() } catch { print("Can't remove \(error)") - // todo: show error alert! + // TODO: show error alert! } } private func onTapUpdateAddress(address: ContactAddress? = nil) { - let onSaveAddress: (ContactAddress?) -> () = { [weak self] updatedAddress in + let onSaveAddress: (ContactAddress?) -> Void = { [weak self] updatedAddress in if let updatedAddress { self?.viewModel.updateContact(address: updatedAddress) } else { @@ -181,100 +182,97 @@ class ContactBookContactViewController: KeyboardAwareViewController { present(controller, animated: true) } - } extension ContactBookContactViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [ Section( - id: "name", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: nameCell, - id: "name", - dynamicHeight: { [weak self] width in - self?.nameCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: nameCautionCell, - id: "name-caution", - dynamicHeight: { [weak self] width in - self?.nameCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - )] + id: "name", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: nameCell, + id: "name", + dynamicHeight: { [weak self] width in + self?.nameCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: nameCautionCell, + id: "name-caution", + dynamicHeight: { [weak self] width in + self?.nameCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), + ] if !addressViewItems.isEmpty { sections.append( - Section( - id: "addresses", - footerState: .margin(height: .margin32), - rows: addressViewItems.enumerated().map({ (index, viewItem) -> RowProtocol in - CellComponent.blockchainAddress( - tableView: tableView, - rowInfo: RowInfo(index: index, count: addressViewItems.count), - imageUrl: viewItem.blockchainImageUrl, - title: viewItem.blockchainName, - value: viewItem.address, - editType: viewItem.edited ? .edited : .original - ) { [weak self] in - self?.onTapUpdateAddress(address: ContactAddress(blockchainUid: viewItem.blockchainUid, address: viewItem.address)) - } - }) - ) + Section( + id: "addresses", + footerState: .margin(height: .margin32), + rows: addressViewItems.enumerated().map { index, viewItem -> RowProtocol in + CellComponent.blockchainAddress( + tableView: tableView, + rowInfo: RowInfo(index: index, count: addressViewItems.count), + imageUrl: viewItem.blockchainImageUrl, + title: viewItem.blockchainName, + value: viewItem.address, + editType: viewItem.edited ? .edited : .original + ) { [weak self] in + self?.onTapUpdateAddress(address: ContactAddress(blockchainUid: viewItem.blockchainUid, address: viewItem.address)) + } + } + ) ) } var cells = [RowProtocol]() if !addAddressHidden { cells.append( - tableView.universalRow48( - id: "add_address", - image: .local(UIImage(named: "plus_24")?.withTintColor(.themeJacob)), - title: .body("contacts.contact.add_address".localized, color: .themeJacob), - autoDeselect: true, - isFirst: true, - isLast: deleteContactHidden, - action: { [weak self] in - self?.onTapUpdateAddress() - } - ) + tableView.universalRow48( + id: "add_address", + image: .local(UIImage(named: "plus_24")?.withTintColor(.themeJacob)), + title: .body("contacts.contact.add_address".localized, color: .themeJacob), + autoDeselect: true, + isFirst: true, + isLast: deleteContactHidden, + action: { [weak self] in + self?.onTapUpdateAddress() + } + ) ) } if !deleteContactHidden { cells.append( - tableView.universalRow48( - id: "delete_contact", - image: .local(UIImage(named: "trash_24")?.withTintColor(.themeLucian)), - title: .body("contacts.contact.delete".localized, color: .themeLucian), - autoDeselect: true, - isFirst: addAddressHidden, - isLast: true, - action: { [weak self] in - self?.onTapDeleteContact() - } - ) + tableView.universalRow48( + id: "delete_contact", + image: .local(UIImage(named: "trash_24")?.withTintColor(.themeLucian)), + title: .body("contacts.contact.delete".localized, color: .themeLucian), + autoDeselect: true, + isFirst: addAddressHidden, + isLast: true, + action: { [weak self] in + self?.onTapDeleteContact() + } + ) ) } if !cells.isEmpty { sections.append(Section(id: "actions", - footerState: .margin(height: .margin32), - rows: cells) + footerState: .margin(height: .margin32), + rows: cells) ) } return sections } - } extension ContactBookContactViewController: IDynamicHeightCellDelegate { - func onChangeHeight() { guard isLoaded else { return @@ -285,5 +283,4 @@ extension ContactBookContactViewController: IDynamicHeightCellDelegate { self?.tableView.endUpdates() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewModel.swift index 574cb5ed6b..0e5f000637 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookContact/ContactBookContactViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class ContactBookContactViewModel { private let disposeBag = DisposeBag() @@ -49,28 +49,26 @@ class ContactBookContactViewModel { private func sync(addressItems: [ContactBookContactService.AddressItem]) { addressViewItems = addressItems.sorted { item, item2 in - if item.edited != item2.edited { - return item.edited - } - return item.blockchain.type.order < item2.blockchain.type.order - } - .map { viewItem(item: $0) } + if item.edited != item2.edited { + return item.edited + } + return item.blockchain.type.order < item2.blockchain.type.order + } + .map { viewItem(item: $0) } } private func viewItem(item: ContactBookContactService.AddressItem) -> AddressViewItem { AddressViewItem( - blockchainUid: item.blockchain.uid, - blockchainImageUrl: item.blockchain.type.imageUrl, - blockchainName: item.blockchain.name, - address: item.address, - edited: item.edited + blockchainUid: item.blockchain.uid, + blockchainImageUrl: item.blockchain.type.imageUrl, + blockchainName: item.blockchain.name, + address: item.address, + edited: item.edited ) } - } extension ContactBookContactViewModel { - var existAddresses: [ContactAddress] { service.addresses } @@ -130,11 +128,9 @@ extension ContactBookContactViewModel { func delete() throws { try service.delete() } - } extension ContactBookContactViewModel { - struct AddressViewItem { let blockchainUid: String let blockchainImageUrl: String @@ -147,5 +143,4 @@ extension ContactBookContactViewModel { let name: String let addresses: [AddressViewItem] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookHelper.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookHelper.swift index e8bc5abb42..32e60b0cd2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookHelper.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookHelper.swift @@ -84,7 +84,7 @@ extension ContactBookHelper { name = RestoreFileHelper.resolve( name: contact.name, - elements: updatedContacts.map { $0.name }, + elements: updatedContacts.map(\.name), style: "(%d)" ) } @@ -99,9 +99,9 @@ extension ContactBookHelper { } return ContactBook( - version: (book?.version ?? 0) + 1, - contacts: updatedContacts, - deletedContacts: book?.deleted ?? [] + version: (book?.version ?? 0) + 1, + contacts: updatedContacts, + deletedContacts: book?.deleted ?? [] ) } @@ -149,7 +149,7 @@ extension ContactBookHelper { let likeLhs = identical(lhs: lhs, rhs: newBook) let likeRhs = identical(lhs: rhs, rhs: newBook) - if likeLhs && likeRhs { + if likeLhs, likeRhs { return .equal } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookModule.swift index b2f5685c41..c245edb6fb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookModule.swift @@ -1,15 +1,14 @@ -import UIKit -import ThemeKit import ComponentKit import MarketKit import MobileCoreServices +import ThemeKit +import UIKit protocol ContactBookSelectorDelegate: AnyObject { func onFetch(address: String) } -struct ContactBookModule { - +enum ContactBookModule { private static func showAddContact(mode: ContactBookModule.AddContactMode, contactAddress: ContactAddress, parentViewController: UIViewController?) { switch mode { case .new: @@ -27,16 +26,16 @@ struct ContactBookModule { } } - private static func chooseAddContactMode(resultAfterClose: Bool, action: ((AddContactMode) -> ())?) -> UIViewController { + private static func chooseAddContactMode(resultAfterClose: Bool, action: ((AddContactMode) -> Void)?) -> UIViewController { let alertViewItems = [ AlertViewItem(text: "contacts.add_address.create_new".localized, selected: false), - AlertViewItem(text: "contacts.add_address.add_to_contact".localized, selected: false) + AlertViewItem(text: "contacts.add_address.add_to_contact".localized, selected: false), ] return AlertRouter.module( - title: "contacts.add_address.title".localized, - viewItems: alertViewItems, - afterClose: resultAfterClose + title: "contacts.add_address.title".localized, + viewItems: alertViewItems, + afterClose: resultAfterClose ) { index in switch index { case 0: action?(.new) @@ -44,11 +43,9 @@ struct ContactBookModule { } } } - } extension ContactBookModule { - static func viewController(mode: Mode, presented: Bool = false) -> UIViewController? { let service = ContactBookService(marketKit: App.shared.marketKit, contactManager: App.shared.contactManager, blockchainType: mode.blockchainType) let viewModel = ContactBookViewModel(service: service) @@ -75,11 +72,9 @@ extension ContactBookModule { parentViewController?.present(alertController, animated: true) } - } extension ContactBookModule { - enum Mode { case edit case select(BlockchainType, ContactBookSelectorDelegate) @@ -87,14 +82,14 @@ extension ContactBookModule { var blockchainType: BlockchainType? { switch self { - case .select(let blockchainType, _): return blockchainType + case let .select(blockchainType, _): return blockchainType default: return nil } } var delegate: ContactBookSelectorDelegate? { switch self { - case .select(_, let delegate): return delegate + case let .select(_, delegate): return delegate default: return nil } } @@ -116,5 +111,4 @@ extension ContactBookModule { case restore case backup } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookService.swift index c0f36eda08..0abadbb634 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookService.swift @@ -1,8 +1,8 @@ +import EvmKit import Foundation -import RxSwift -import RxRelay import MarketKit -import EvmKit +import RxRelay +import RxSwift class ContactBookService { private let disposeBag = DisposeBag() @@ -61,7 +61,7 @@ class ContactBookService { subscribe(disposeBag, contactManager.stateObservable) { [weak self] _ in self?.sync() } subscribe(disposeBag, contactManager.iCloudErrorObservable) { [weak self] error in - if error != nil, (self?.contactManager.remoteSync ?? false) { + if error != nil, self?.contactManager.remoteSync ?? false { self?.iCloudAvailableErrorRelay.accept(true) } else { self?.iCloudAvailableErrorRelay.accept(false) @@ -75,15 +75,13 @@ class ContactBookService { if let contacts = contactManager.all { _contacts = contacts } else { - // todo: show alert ? + // TODO: show alert ? print("Can't load contacts!") } } - } extension ContactBookService { - var itemsObservable: Observable<[Item]> { itemsRelay.asObservable() } @@ -100,8 +98,8 @@ extension ContactBookService { func contactAddress(contactUid: String, blockchainUid: String) -> ContactAddress? { _contacts - .first(where: { contact in contact.uid == contactUid })? - .address(blockchainUid: blockchainUid) + .first(where: { contact in contact.uid == contactUid })? + .address(blockchainUid: blockchainUid) } func delete(contactUid: String) throws { @@ -111,11 +109,9 @@ extension ContactBookService { func blockchainName(blockchainUid: String) -> String? { try? marketKit.blockchain(uid: blockchainUid)?.name } - } extension ContactBookService { - class Item: Comparable { let uid: String let name: String @@ -125,11 +121,11 @@ extension ContactBookService { self.name = name } - static func <(lhs: Item, rhs: Item) -> Bool { + static func < (lhs: Item, rhs: Item) -> Bool { lhs.name < rhs.name } - static func ==(lhs: Item, rhs: Item) -> Bool { + static func == (lhs: Item, rhs: Item) -> Bool { lhs.uid == rhs.uid } } @@ -138,7 +134,7 @@ extension ContactBookService { let blockchainAddress: String init(uid: String, name: String, address: String) { - self.blockchainAddress = address + blockchainAddress = address super.init(uid: uid, name: name) } } @@ -151,5 +147,4 @@ extension ContactBookService { super.init(uid: uid, name: name) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewController.swift index 06c267eb45..833b837a12 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewController.swift @@ -1,11 +1,11 @@ import Combine -import UIKit -import RxSwift -import RxCocoa -import SnapKit import ComponentKit +import RxCocoa +import RxSwift import SectionsTableView +import SnapKit import ThemeKit +import UIKit class ContactBookViewController: ThemeSearchViewController { private let viewModel: ContactBookViewModel @@ -32,7 +32,8 @@ class ContactBookViewController: ThemeSearchViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -85,10 +86,10 @@ class ContactBookViewController: ThemeSearchViewController { // show add button on empty screen only for edit mode if mode.editable { notFoundPlaceholder.addPrimaryButton( - style: .yellow, - title: "contacts.add_new_contact".localized, - target: self, - action: #selector(onCreateContact) + style: .yellow, + title: "contacts.add_new_contact".localized, + target: self, + action: #selector(onCreateContact) ) } @@ -97,10 +98,9 @@ class ContactBookViewController: ThemeSearchViewController { subscribe(disposeBag, viewModel.showBadgeDriver) { [weak self] in self?.manageBarButtonView.isBadgeHidden = !$0 } $filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } - .store(in: &cancellables) - + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } + .store(in: &cancellables) tableView.buildSections() @@ -136,14 +136,14 @@ class ContactBookViewController: ThemeSearchViewController { switch mode { case .edit: onUpdateContact(contactUid: viewItem.uid) - case .select(_, let delegate): + case let .select(_, delegate): if let viewItem = viewItem as? ContactBookViewModel.SelectorViewItem { delegate.onFetch(address: viewItem.address) } onClose() - case .addToContact(let address): - let updateContact: () -> () = { [weak self] in - let successAction: (() -> ())? = { [weak self] in + case let .addToContact(address): + let updateContact: () -> Void = { [weak self] in + let successAction: (() -> Void)? = { [weak self] in self?.onClose() } self?.onUpdateContact(contactUid: viewItem.uid, newAddress: address, onUpdateContact: successAction) @@ -152,30 +152,30 @@ class ContactBookViewController: ThemeSearchViewController { if let currentAddress = viewModel.contactAddress(contactUid: viewItem.uid, blockchainUid: address.blockchainUid) { updateAfterAlert(new: address, old: currentAddress, onSuccess: updateContact) } else { - updateContact() + updateContact() } } } - private func updateAfterAlert(new: ContactAddress, old: ContactAddress, onSuccess: (() -> ())?) { + private func updateAfterAlert(new: ContactAddress, old: ContactAddress, onSuccess: (() -> Void)?) { let blockchainName = viewModel.blockchainName(blockchainUid: new.blockchainUid) ?? "" let viewController = BottomSheetModule.viewController( - image: .warning, - title: "alert.warning".localized, - items: [ - .highlightedDescription(text: "contacts.update_contact.already_has_address".localized(blockchainName, old.address.shortened, new.address.shortened)) - ], - buttons: [ - .init(style: .yellow, title: "contacts.update_contact.replace".localized, actionType: .afterClose) { - onSuccess?() - }, - .init(style: .transparent, title: "button.cancel".localized) - ] + image: .warning, + title: "alert.warning".localized, + items: [ + .highlightedDescription(text: "contacts.update_contact.already_has_address".localized(blockchainName, old.address.shortened, new.address.shortened)), + ], + buttons: [ + .init(style: .yellow, title: "contacts.update_contact.replace".localized, actionType: .afterClose) { + onSuccess?() + }, + .init(style: .transparent, title: "button.cancel".localized), + ] ) present(viewController, animated: true) } - private func onUpdateContact(contactUid: String? = nil, newAddress: ContactAddress? = nil, onUpdateContact: (() -> ())? = nil) { + private func onUpdateContact(contactUid: String? = nil, newAddress: ContactAddress? = nil, onUpdateContact: (() -> Void)? = nil) { let mode: ContactBookContactModule.Mode let newAddresses = [newAddress].compactMap { $0 } if let contactUid { @@ -191,7 +191,7 @@ class ContactBookViewController: ThemeSearchViewController { } private func onUpdate(viewItems: [ContactBookViewModel.ViewItem]) { - let animated = self.viewItems.map { $0.uid } == viewItems.map { $0.uid } + let animated = self.viewItems.map(\.uid) == viewItems.map(\.uid) self.viewItems = viewItems tableView.reload(animated: isLoaded && animated) @@ -212,14 +212,13 @@ class ContactBookViewController: ThemeSearchViewController { case .none: notFoundPlaceholder.isHidden = true } - } private func deleteRowAction(uid: String) -> RowAction { RowAction(pattern: .icon( - image: UIImage(named: "circle_minus_shifted_24"), - background: UIColor(red: 0, green: 0, blue: 0, alpha: 0) - ), action: { [weak self] cell in + image: UIImage(named: "circle_minus_shifted_24"), + background: UIColor(red: 0, green: 0, blue: 0, alpha: 0) + ), action: { [weak self] _ in self?.removeContact(uid: uid) }) } @@ -231,24 +230,23 @@ class ContactBookViewController: ThemeSearchViewController { print("Can't remove contact \(error)") } } - } extension ContactBookViewController: SectionsDataSource { - private func cell(viewItem: ContactBookViewModel.ViewItem, isFirst: Bool, isLast: Bool) -> RowProtocol { let rowAction = deleteRowAction(uid: viewItem.uid) return tableView.universalRow62( - id: viewItem.uid, - title: .body(viewItem.title), - description: .subhead2(viewItem.subtitle), - accessoryType: .disclosure, - hash: viewItem.description + isFirst.description + isLast.description, - autoDeselect: true, - rowActionProvider: { [ rowAction ] }, - isFirst: isFirst, - isLast: isLast) { [weak self] in + id: viewItem.uid, + title: .body(viewItem.title), + description: .subhead2(viewItem.subtitle), + accessoryType: .disclosure, + hash: viewItem.description + isFirst.description + isLast.description, + autoDeselect: true, + rowActionProvider: { [rowAction] }, + isFirst: isFirst, + isLast: isLast + ) { [weak self] in self?.onTap(viewItem: viewItem) } } @@ -256,15 +254,14 @@ extension ContactBookViewController: SectionsDataSource { func buildSections() -> [SectionProtocol] { [ Section( - id: "coins", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - let isLast = index == viewItems.count - 1 - return cell(viewItem: viewItem, isFirst: index == 0, isLast: isLast) - } - ) + id: "coins", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + let isLast = index == viewItems.count - 1 + return cell(viewItem: viewItem, isFirst: index == 0, isLast: isLast) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewModel.swift index 79432dc17b..a069501ffa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ContactBookViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class ContactBookViewModel { private let service: ContactBookService @@ -28,20 +28,20 @@ class ContactBookViewModel { viewItems = items.map { item in switch item { case let item as ContactBookService.ReadOnlyItem: - return SelectorViewItem( - uid: item.uid, - title: item.name, - subtitle: item.blockchainAddress.shortened, - showDisclosure: false, - address: item.blockchainAddress - ) + return SelectorViewItem( + uid: item.uid, + title: item.name, + subtitle: item.blockchainAddress.shortened, + showDisclosure: false, + address: item.blockchainAddress + ) case let item as ContactBookService.EditableItem: - return ViewItem( - uid: item.uid, - title: item.name, - subtitle: "contacts.list.addresses_count".localized(item.addressCount), - showDisclosure: false - ) + return ViewItem( + uid: item.uid, + title: item.name, + subtitle: "contacts.list.addresses_count".localized(item.addressCount), + showDisclosure: false + ) default: return ViewItem(uid: item.uid, title: item.name, subtitle: "", showDisclosure: true) } @@ -53,11 +53,9 @@ class ContactBookViewModel { emptyListRelay.accept(nil) } } - } extension ContactBookViewModel { - var viewItemsDriver: Driver<[ViewItem]> { viewItemsRelay.asDriver() } @@ -87,11 +85,9 @@ extension ContactBookViewModel { func blockchainName(blockchainUid: String) -> String? { service.blockchainName(blockchainUid: blockchainUid) } - } extension ContactBookViewModel { - class ViewItem { let uid: String let title: String @@ -122,5 +118,4 @@ extension ContactBookViewModel { case emptyBook case emptySearch } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ManageBarButtonView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ManageBarButtonView.swift index e0382810e6..7082ff7587 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ManageBarButtonView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookList/ManageBarButtonView.swift @@ -1,13 +1,13 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class ManageBarButtonView: UIView { private let button = UIButton() private let badgeView = UIView() - var onTap: (() -> ())? + var onTap: (() -> Void)? init() { super.init(frame: .zero) @@ -30,18 +30,17 @@ class ManageBarButtonView: UIView { button.addTarget(self, action: #selector(onTapButton), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func onTapButton() { onTap?() } - } extension ManageBarButtonView { - var isBadgeHidden: Bool { get { badgeView.isHidden @@ -50,5 +49,4 @@ extension ManageBarButtonView { badgeView.isHidden = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsModule.swift index c74aa939a7..81713ecdd9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsModule.swift @@ -1,11 +1,9 @@ import UIKit class ContactBookSettingsModule { - static var viewController: UIViewController? { let service = ContactBookSettingsService(contactManager: App.shared.contactManager) let viewModel = ContactBookSettingsViewModel(service: service) return ContactBookSettingsViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsService.swift index e13ca5057a..df85d30ad5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsService.swift @@ -7,7 +7,7 @@ class ContactBookSettingsService { private let contactManager: ContactBookManager private let activatedChangedRelay = BehaviorRelay(value: false) - private let confirmationRelay = PublishRelay<()>() + private let confirmationRelay = PublishRelay() private let cloudErrorRelay = BehaviorRelay(value: nil) var cloudError: Error? { @@ -16,7 +16,7 @@ class ContactBookSettingsService { } } - private var needToMerge: Bool { // when remote sync not enabled yet and user has contacts + private var needToMerge: Bool { // when remote sync not enabled yet and user has contacts !(contactManager.remoteSync || (contactManager.all?.isEmpty ?? true)) } @@ -32,11 +32,9 @@ class ContactBookSettingsService { private func sync(error: Error?) { cloudError = error } - } extension ContactBookSettingsService { - var hasContacts: Bool { guard let contactBook = contactManager.state.data else { return false @@ -84,7 +82,7 @@ extension ContactBookSettingsService { } } - var confirmationObservable: Observable<()> { + var confirmationObservable: Observable { confirmationRelay.asObservable() } @@ -117,14 +115,11 @@ extension ContactBookSettingsService { return temporaryFileUrl } - } extension ContactBookSettingsService { - enum CreateBackupFileError: Error { case noBackupContactBook case noTempFileUrl } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewController.swift index 8feb7b4218..3dbe228a3f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import UniformTypeIdentifiers -import SectionsTableView -import ThemeKit import ComponentKit import RxSwift +import SectionsTableView +import ThemeKit +import UIKit +import UniformTypeIdentifiers class ContactBookSettingsViewController: ThemeViewController { private let disposeBag = DisposeBag() @@ -21,7 +21,8 @@ class ContactBookSettingsViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -74,17 +75,17 @@ class ContactBookSettingsViewController: ThemeViewController { private func showRestoreAlert(contacts: [BackupContact]) { let viewController = BottomSheetModule.viewController( - image: .warning, - title: "alert.warning".localized, - items: [ - .highlightedDescription(text: "contacts.restore.overwrite_alert.description".localized) - ], - buttons: [ - .init(style: .red, title: "contacts.restore.overwrite_alert.replace".localized, actionType: .afterClose) { [weak self] in - self?.viewModel.replace(contacts: contacts) - }, - .init(style: .transparent, title: "button.cancel".localized) - ] + image: .warning, + title: "alert.warning".localized, + items: [ + .highlightedDescription(text: "contacts.restore.overwrite_alert.description".localized), + ], + buttons: [ + .init(style: .red, title: "contacts.restore.overwrite_alert.replace".localized, actionType: .afterClose) { [weak self] in + self?.viewModel.replace(contacts: contacts) + }, + .init(style: .transparent, title: "button.cancel".localized), + ] ) present(viewController, animated: true) } @@ -99,16 +100,16 @@ class ContactBookSettingsViewController: ThemeViewController { private func showMergeConfirmation() { let viewController = BottomSheetModule.viewController( - image: .warning, - title: "alert.warning".localized, - items: [ - .highlightedDescription(text: "contacts.settings.merge_disclaimer".localized) - ], - buttons: [ - .init(style: .yellow, title: "button.continue".localized) { [ weak self] in self?.viewModel.onConfirm() }, - .init(style: .transparent, title: "button.cancel".localized) { [weak self] in self?.bottomSelectorOnDismiss() } - ], - delegate: self + image: .warning, + title: "alert.warning".localized, + items: [ + .highlightedDescription(text: "contacts.settings.merge_disclaimer".localized), + ], + buttons: [ + .init(style: .yellow, title: "button.continue".localized) { [weak self] in self?.viewModel.onConfirm() }, + .init(style: .transparent, title: "button.cancel".localized) { [weak self] in self?.bottomSelectorOnDismiss() }, + ], + delegate: self ) present(viewController, animated: true) @@ -120,21 +121,19 @@ class ContactBookSettingsViewController: ThemeViewController { } } - private func checkICloudAvailable() { - - } + private func checkICloudAvailable() {} private func activationElements(on: Bool, warning: Bool, animated: Bool = false) -> CellBuilderNew.CellElement { var elements = tableView.universalImage24Elements( - title: .body("contacts.settings.icloud_sync".localized), - accessoryType: .switch( - isOn: on, - animated: animated - ) { [weak self] isOn in - self?.viewModel.onToggle(isOn: isOn) - } + title: .body("contacts.settings.icloud_sync".localized), + accessoryType: .switch( + isOn: on, + animated: animated + ) { [weak self] isOn in + self?.viewModel.onToggle(isOn: isOn) + } ) - elements.insert(.image20 { (component: ImageComponent) -> () in + elements.insert(.image20 { (component: ImageComponent) in component.isHidden = !(on && warning) component.imageView.image = UIImage(named: "warning_2_20")?.withTintColor(.themeLucian) }, at: 2) @@ -171,96 +170,89 @@ class ContactBookSettingsViewController: ThemeViewController { HudHelper.instance.show(banner: .error(string: "contacts.restore.storage_error".localized)) } } - } extension ContactBookSettingsViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { let backupVisible = viewModel.hasContacts var manageRows: [RowProtocol] = [ tableView.universalRow48( - id: "restore", - image: .local(UIImage(named: "download_24")?.withTintColor(.themeJacob)), - title: .body("contacts.settings.restore_contacts".localized, color: .themeJacob), - autoDeselect: true, - isFirst: true, - isLast: !backupVisible, - action: { [weak self] in - self?.onTapRestore() - } - ) + id: "restore", + image: .local(UIImage(named: "download_24")?.withTintColor(.themeJacob)), + title: .body("contacts.settings.restore_contacts".localized, color: .themeJacob), + autoDeselect: true, + isFirst: true, + isLast: !backupVisible, + action: { [weak self] in + self?.onTapRestore() + } + ), ] if backupVisible { manageRows.append( - tableView.universalRow48( - id: "backup", - image: .local(UIImage(named: "icloud_24")?.withTintColor(.themeJacob)), - title: .body("contacts.settings.backup_contacts".localized, color: .themeJacob), - autoDeselect: true, - isLast: true, - action: { [weak self] in - self?.onTapBackup() - } - ) + tableView.universalRow48( + id: "backup", + image: .local(UIImage(named: "icloud_24")?.withTintColor(.themeJacob)), + title: .body("contacts.settings.backup_contacts".localized, color: .themeJacob), + autoDeselect: true, + isLast: true, + action: { [weak self] in + self?.onTapBackup() + } + ) ) } var sections: [SectionProtocol] = [ Section( - id: "manage-contacts", - headerState: .margin(height: .margin12), - rows: manageRows + id: "manage-contacts", + headerState: .margin(height: .margin12), + rows: manageRows ), Section( - id: "activate_section", - headerState: .margin(height: .margin32), - footerState: tableView.sectionFooter(text: "contacts.settings.description".localized), - rows: [ - CellBuilderNew.row( - rootElement: activationElements(on: viewModel.featureEnabled, warning: lostSynchronization), - tableView: tableView, - id: "activate-icloud-contacts", - height: .heightCell48, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - } - ) - ] - ) + id: "activate_section", + headerState: .margin(height: .margin32), + footerState: tableView.sectionFooter(text: "contacts.settings.description".localized), + rows: [ + CellBuilderNew.row( + rootElement: activationElements(on: viewModel.featureEnabled, warning: lostSynchronization), + tableView: tableView, + id: "activate-icloud-contacts", + height: .heightCell48, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + } + ), + ] + ), ] if lostSynchronization { sections.append(Section( - id: "lost_sync_section", - footerState: .margin(height: .margin32), - rows: [ - tableView.highlightedDescriptionRow(id: "lost_connection", style: .red, text: "contacts.settings.lost_synchronization.description".localized) - ] + id: "lost_sync_section", + footerState: .margin(height: .margin32), + rows: [ + tableView.highlightedDescriptionRow(id: "lost_connection", style: .red, text: "contacts.settings.lost_synchronization.description".localized), + ] )) } return sections } - } extension ContactBookSettingsViewController: IBottomSheetDismissDelegate { - func bottomSelectorOnDismiss() { setToggle(on: false) } - } extension ContactBookSettingsViewController: UIDocumentPickerDelegate { - - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { if let jsonUrl = urls.first { viewModel.didPick(url: jsonUrl) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewModel.swift index 3d35459923..73781258da 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactBookSettings/ContactBookSettingsViewModel.swift @@ -1,7 +1,7 @@ import Foundation +import RxCocoa import RxRelay import RxSwift -import RxCocoa class ContactBookSettingsViewModel { private let disposeBag = DisposeBag() @@ -9,13 +9,13 @@ class ContactBookSettingsViewModel { private let featureEnabledRelay = BehaviorRelay(value: false) - private let showConfirmationRelay = PublishRelay<()>() + private let showConfirmationRelay = PublishRelay() private let showSyncErrorRelay = BehaviorRelay(value: false) private let showRestoreAlertRelay = PublishRelay<[BackupContact]>() - private let showParsingErrorRelay = PublishRelay<()>() - private let showSuccessfulRestoreRelay = PublishRelay<()>() - private let showRestoreErrorRelay = PublishRelay<()>() + private let showParsingErrorRelay = PublishRelay() + private let showSuccessfulRestoreRelay = PublishRelay() + private let showRestoreErrorRelay = PublishRelay() init(service: ContactBookSettingsService) { self.service = service @@ -36,23 +36,22 @@ class ContactBookSettingsViewModel { showSyncErrorRelay.accept(false) } } - } -extension ContactBookSettingsViewModel { +extension ContactBookSettingsViewModel { var showRestoreAlertSignal: Signal<[BackupContact]> { showRestoreAlertRelay.asSignal() } - var showParsingErrorSignal: Signal<()> { + var showParsingErrorSignal: Signal { showParsingErrorRelay.asSignal() } - var showSuccessfulRestoreSignal: Signal<()> { + var showSuccessfulRestoreSignal: Signal { showSuccessfulRestoreRelay.asSignal() } - var showRestoreErrorSignal: Signal<()> { + var showRestoreErrorSignal: Signal { showRestoreErrorRelay.asSignal() } @@ -68,7 +67,7 @@ extension ContactBookSettingsViewModel { featureEnabledRelay.asDriver() } - var showConfirmationSignal: Signal<()> { + var showConfirmationSignal: Signal { showConfirmationRelay.asSignal() } @@ -105,5 +104,4 @@ extension ContactBookSettingsViewModel { func createBackupFile() throws -> URL { try service.createBackupFile() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactLabelService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactLabelService.swift index 79d494ef40..0c9da62513 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactLabelService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/ContactLabelService.swift @@ -1,7 +1,7 @@ import Foundation import MarketKit -import RxSwift import RxRelay +import RxSwift class ContactLabelService { private let disposeBag = DisposeBag() @@ -43,11 +43,9 @@ class ContactLabelService { } } } - } extension ContactLabelService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -62,11 +60,9 @@ extension ContactLabelService { } return ContactData(name: nil, contactAddress: ContactAddress(blockchainUid: blockchainType.uid, address: address)) } - } extension ContactLabelService { - enum State { case idle case exist @@ -77,5 +73,4 @@ extension ContactLabelService { let name: String? let contactAddress: ContactAddress? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/TransactionsContactLabelService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/TransactionsContactLabelService.swift index 672092e1a1..1ad2af47b1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/TransactionsContactLabelService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ContactBook/TransactionsContactLabelService.swift @@ -1,7 +1,7 @@ import Foundation import MarketKit -import RxSwift import RxRelay +import RxSwift class TransactionsContactLabelService { private let disposeBag = DisposeBag() @@ -29,11 +29,9 @@ class TransactionsContactLabelService { } state = .updatedBook } - } extension TransactionsContactLabelService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -44,11 +42,9 @@ extension TransactionsContactLabelService { } return ContactData(name: nil, contactAddress: ContactAddress(blockchainUid: blockchainType.uid, address: address)) } - } extension TransactionsContactLabelService { - enum State { case idle case updatedBook @@ -58,5 +54,4 @@ extension TransactionsContactLabelService { let name: String? let contactAddress: ContactAddress? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountAdvancedViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountAdvancedViewController.swift index a2f4850222..d1e5ec8c3c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountAdvancedViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountAdvancedViewController.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit +import ComponentKit +import HUD +import RxCocoa +import RxSwift import SectionsTableView import SnapKit -import RxSwift -import RxCocoa -import HUD -import ComponentKit +import ThemeKit import UIExtensions +import UIKit protocol ICreateAccountListener: UIViewController { func handleCreateAccount() @@ -40,7 +40,8 @@ class CreateAccountAdvancedViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -78,14 +79,14 @@ class CreateAccountAdvancedViewController: KeyboardAwareViewController { passphraseToggleCell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) CellBuilderNew.buildStatic( - cell: passphraseToggleCell, - rootElement: .hStack( - tableView.universalImage24Elements( - image: .local(UIImage(named: "key_phrase_24")?.withTintColor(.themeGray)), - title: .body("create_wallet.passphrase".localized), - accessoryType: .switch { [weak self] in self?.viewModel.onTogglePassphrase(isOn: $0) } - ) + cell: passphraseToggleCell, + rootElement: .hStack( + tableView.universalImage24Elements( + image: .local(UIImage(named: "key_phrase_24")?.withTintColor(.themeGray)), + title: .body("create_wallet.passphrase".localized), + accessoryType: .switch { [weak self] in self?.viewModel.onTogglePassphrase(isOn: $0) } ) + ) ) passphraseCell.set(textSecure: true) @@ -156,7 +157,7 @@ class CreateAccountAdvancedViewController: KeyboardAwareViewController { private func finish() { HudHelper.instance.show(banner: .created) - if let listener = listener { + if let listener { listener.handleCreateAccount() } else { dismiss(animated: true) @@ -180,118 +181,116 @@ class CreateAccountAdvancedViewController: KeyboardAwareViewController { tableView.beginUpdates() tableView.endUpdates() } - } extension CreateAccountAdvancedViewController: SectionsDataSource { - private func sync(cell: BaseThemeCell, image: UIImage?, title: String, value: String) { CellBuilderNew.buildStatic( - cell: cell, - rootElement: .hStack( - tableView.universalImage24Elements( - image: .local(image?.withTintColor(.themeGray)), - title: .body(title), - value: .subhead1(value, color: .themeGray), - accessoryType: .dropdown - ) + cell: cell, + rootElement: .hStack( + tableView.universalImage24Elements( + image: .local(image?.withTintColor(.themeGray)), + title: .body(title), + value: .subhead1(value, color: .themeGray), + accessoryType: .dropdown ) + ) ) } private func syncMnemonicCell(wordCount: String) { sync( - cell: mnemonicCell, - image: UIImage(named: "key_24"), - title: "create_wallet.phrase_count".localized, - value: wordCount + cell: mnemonicCell, + image: UIImage(named: "key_24"), + title: "create_wallet.phrase_count".localized, + value: wordCount ) } func buildSections() -> [SectionProtocol] { var sections: [SectionProtocol] = [ Section( - id: "margin", - headerState: .margin(height: .margin12) + id: "margin", + headerState: .margin(height: .margin12) ), Section( - id: "name", - headerState: tableView.sectionHeader(text: "create_wallet.name".localized), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: nameCell, - id: "name", - height: .heightSingleLineCell - ) - ] + id: "name", + headerState: tableView.sectionHeader(text: "create_wallet.name".localized), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: nameCell, + id: "name", + height: .heightSingleLineCell + ), + ] ), Section( - id: "mnemonic", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: mnemonicCell, - id: "mnemonic", - height: .heightCell48, - autoDeselect: true, - action: { [weak self] in - self?.openWordCountSelector() - } - ) - ] + id: "mnemonic", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: mnemonicCell, + id: "mnemonic", + height: .heightCell48, + autoDeselect: true, + action: { [weak self] in + self?.openWordCountSelector() + } + ), + ] ), Section( - id: "passphrase-toggle", - footerState: .margin(height: inputsVisible ? .margin24 : .margin32), - rows: [ - StaticRow( - cell: passphraseToggleCell, - id: "passphrase-toggle", - height: .heightCell48 - ) - ] - ) + id: "passphrase-toggle", + footerState: .margin(height: inputsVisible ? .margin24 : .margin32), + rows: [ + StaticRow( + cell: passphraseToggleCell, + id: "passphrase-toggle", + height: .heightCell48 + ), + ] + ), ] if inputsVisible { let inputSections: [SectionProtocol] = [ Section( - id: "passphrase", - footerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: passphraseCell, - id: "passphrase", - height: .heightSingleLineCell - ), - StaticRow( - cell: passphraseCautionCell, - id: "passphrase-caution", - dynamicHeight: { [weak self] width in - self?.passphraseCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "passphrase", + footerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: passphraseCell, + id: "passphrase", + height: .heightSingleLineCell + ), + StaticRow( + cell: passphraseCautionCell, + id: "passphrase-caution", + dynamicHeight: { [weak self] width in + self?.passphraseCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "passphrase-confirmation", - footerState: tableView.sectionFooter(text: "create_wallet.passphrase_description".localized), - rows: [ - StaticRow( - cell: passphraseConfirmationCell, - id: "passphrase-confirmation", - height: .heightSingleLineCell - ), - StaticRow( - cell: passphraseConfirmationCautionCell, - id: "passphrase-confirmation-caution", - dynamicHeight: { [weak self] width in - self?.passphraseConfirmationCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + id: "passphrase-confirmation", + footerState: tableView.sectionFooter(text: "create_wallet.passphrase_description".localized), + rows: [ + StaticRow( + cell: passphraseConfirmationCell, + id: "passphrase-confirmation", + height: .heightSingleLineCell + ), + StaticRow( + cell: passphraseConfirmationCautionCell, + id: "passphrase-confirmation-caution", + dynamicHeight: { [weak self] width in + self?.passphraseConfirmationCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), ] sections.append(contentsOf: inputSections) @@ -299,5 +298,4 @@ extension CreateAccountAdvancedViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountModule.swift index c0d59fa99a..7bfe76805e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountModule.swift @@ -1,16 +1,15 @@ -import UIKit import ThemeKit +import UIKit struct CreateAccountModule { - static func viewController(advanced: Bool = false, sourceViewController: UIViewController? = nil, listener: ICreateAccountListener? = nil) -> UIViewController { let service = CreateAccountService( - accountFactory: App.shared.accountFactory, - predefinedBlockchainService: App.shared.predefinedBlockchainService, - languageManager: LanguageManager.shared, - accountManager: App.shared.accountManager, - walletManager: App.shared.walletManager, - marketKit: App.shared.marketKit + accountFactory: App.shared.accountFactory, + predefinedBlockchainService: App.shared.predefinedBlockchainService, + languageManager: LanguageManager.shared, + accountManager: App.shared.accountManager, + walletManager: App.shared.walletManager, + marketKit: App.shared.marketKit ) let viewModel = CreateAccountViewModel(service: service) @@ -28,5 +27,4 @@ struct CreateAccountModule { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountService.swift index 912904541e..03ccde5766 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import MarketKit import HdWalletKit +import MarketKit +import RxRelay +import RxSwift class CreateAccountService { private let accountFactory: AccountFactory @@ -35,11 +35,11 @@ class CreateAccountService { private func activateDefaultWallets(account: Account) throws { let tokenQueries = [ - TokenQuery(blockchainType: .bitcoin, tokenType: .derived(derivation: .bip84)), //todo: make derivation supports accountType + TokenQuery(blockchainType: .bitcoin, tokenType: .derived(derivation: .bip84)), // TODO: make derivation supports accountType TokenQuery(blockchainType: .ethereum, tokenType: .native), TokenQuery(blockchainType: .binanceSmartChain, tokenType: .native), TokenQuery(blockchainType: .ethereum, tokenType: .eip20(address: "0xdac17f958d2ee523a2206206994597c13d831ec7")), // USDT - TokenQuery(blockchainType: .binanceSmartChain, tokenType: .eip20(address: "0xe9e7cea3dedca5984780bafc599bd69add087d56")) // BUSD + TokenQuery(blockchainType: .binanceSmartChain, tokenType: .eip20(address: "0xe9e7cea3dedca5984780bafc599bd69add087d56")), // BUSD ] var wallets = [Wallet]() @@ -51,11 +51,9 @@ class CreateAccountService { walletManager.save(wallets: wallets) } - } extension CreateAccountService { - var wordCountObservable: Observable { wordCountRelay.asObservable() } @@ -96,11 +94,11 @@ extension CreateAccountService { let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) let account = accountFactory.account( - type: accountType, - origin: .created, - backedUp: false, - fileBackedUp: false, - name: trimmedName.isEmpty ? defaultAccountName : trimmedName + type: accountType, + origin: .created, + backedUp: false, + fileBackedUp: false, + name: trimmedName.isEmpty ? defaultAccountName : trimmedName ) accountManager.save(account: account) @@ -108,14 +106,11 @@ extension CreateAccountService { accountManager.set(lastCreatedAccount: account) } - } extension CreateAccountService { - enum CreateError: Error { case emptyPassphrase case invalidConfirmation } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountSimpleViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountSimpleViewController.swift index a718d93b08..87ef8edcc7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountSimpleViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountSimpleViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import RxSwift +import ComponentKit import RxCocoa +import RxSwift +import SectionsTableView import SnapKit import ThemeKit -import ComponentKit -import SectionsTableView import UIExtensions +import UIKit class CreateAccountSimpleViewController: KeyboardAwareViewController { private let viewModel: CreateAccountViewModel @@ -27,7 +27,8 @@ class CreateAccountSimpleViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -99,36 +100,33 @@ class CreateAccountSimpleViewController: KeyboardAwareViewController { private func finish() { HudHelper.instance.show(banner: .created) - if let listener = listener { + if let listener { listener.handleCreateAccount() } else { dismiss(animated: true) } } - } extension CreateAccountSimpleViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "margin", - headerState: .margin(height: .margin12) + id: "margin", + headerState: .margin(height: .margin12) ), Section( - id: "name", - headerState: tableView.sectionHeader(text: "create_wallet.name".localized), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: nameCell, - id: "name", - height: .heightSingleLineCell - ) - ] - ) + id: "name", + headerState: tableView.sectionHeader(text: "create_wallet.name".localized), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: nameCell, + id: "name", + height: .heightSingleLineCell + ), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountViewModel.swift index a88bf5db55..69519f38b4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/CreateAccountViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import HdWalletKit +import RxCocoa +import RxRelay +import RxSwift class CreateAccountViewModel { private let service: CreateAccountService @@ -12,7 +12,7 @@ class CreateAccountViewModel { private let passphraseConfirmationCautionRelay = BehaviorRelay(value: nil) private let clearInputsRelay = PublishRelay() private let showErrorRelay = PublishRelay() - private let finishRelay = PublishRelay<()>() + private let finishRelay = PublishRelay() init(service: CreateAccountService) { self.service = service @@ -43,11 +43,9 @@ class CreateAccountViewModel { passphraseConfirmationCautionRelay.accept(nil) } } - } extension CreateAccountViewModel { - var wordCountDriver: Driver { wordCountRelay.asDriver() } @@ -72,7 +70,7 @@ extension CreateAccountViewModel { showErrorRelay.asSignal() } - var finishSignal: Signal<()> { + var finishSignal: Signal { finishRelay.asSignal() } @@ -147,5 +145,4 @@ extension CreateAccountViewModel { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/PassphraseValidator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/PassphraseValidator.swift index 3e94a55349..a97fefe6c9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/PassphraseValidator.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/CreateAccount/PassphraseValidator.swift @@ -1,14 +1,13 @@ import Foundation class PassphraseValidator { - static private let forbiddenSymbols = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '\"`&/?!:;.,~*$=+-[](){}<>\\_#@|%").inverted + private static let forbiddenSymbols = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '\"`&/?!:;.,~*$=+-[](){}<>\\_#@|%").inverted static func validate(text: String?) -> Bool { - if text?.rangeOfCharacter(from: Self.forbiddenSymbols) != nil { + if text?.rangeOfCharacter(from: forbiddenSymbols) != nil { return false } return true } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugInteractor.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugInteractor.swift index 2a694f7067..3e50557099 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugInteractor.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugInteractor.swift @@ -13,17 +13,15 @@ class DebugInteractor { self.pasteboardManager = pasteboardManager appManager.willEnterForegroundObservable - .observeOn(MainScheduler.instance) - .subscribe(onNext: { [weak self] in - self?.delegate?.didEnterForeground() - }) - .disposed(by: disposeBag) + .observeOn(MainScheduler.instance) + .subscribe(onNext: { [weak self] in + self?.delegate?.didEnterForeground() + }) + .disposed(by: disposeBag) } - } extension DebugInteractor: IDebugInteractor { - var logs: [String] { debugBackgroundManager?.logs ?? ["not available!"] } @@ -31,5 +29,4 @@ extension DebugInteractor: IDebugInteractor { func clearLogs() { debugBackgroundManager?.clearLogs() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugModule.swift index 72b3ddb345..362e16ce8b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugModule.swift @@ -16,5 +16,4 @@ protocol IDebugInteractorDelegate: AnyObject { func didEnterForeground() } -protocol IDebugRouter { -} +protocol IDebugRouter {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugPresenter.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugPresenter.swift index 33563393cd..bb90ac5332 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugPresenter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugPresenter.swift @@ -6,11 +6,9 @@ class DebugPresenter { init(interactor: IDebugInteractor) { self.interactor = interactor } - } extension DebugPresenter: IDebugViewDelegate { - func viewDidLoad() { view?.set(logs: interactor.logs) } @@ -19,13 +17,10 @@ extension DebugPresenter: IDebugViewDelegate { interactor.clearLogs() view?.set(logs: interactor.logs) } - } extension DebugPresenter: IDebugInteractorDelegate { - func didEnterForeground() { view?.set(logs: interactor.logs) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugRouter.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugRouter.swift index bf1df1d33c..c2b8a45800 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugRouter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugRouter.swift @@ -1,13 +1,10 @@ import UIKit -class DebugRouter { -} +class DebugRouter {} -extension DebugRouter: IDebugRouter { -} +extension DebugRouter: IDebugRouter {} extension DebugRouter { - static func module() -> UIViewController { let interactor = DebugInteractor(appManager: App.shared.appManager, debugBackgroundManager: App.shared.debugLogger, pasteboardManager: App.shared.pasteboardManager) let presenter = DebugPresenter(interactor: interactor) @@ -18,5 +15,4 @@ extension DebugRouter { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugViewController.swift index 2ac33983b5..e285b962b5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Debug/DebugViewController.swift @@ -1,5 +1,5 @@ -import UIKit import ThemeKit +import UIKit class DebugViewController: ThemeViewController { private let delegate: IDebugViewDelegate @@ -14,7 +14,8 @@ class DebugViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -35,15 +36,12 @@ class DebugViewController: ThemeViewController { @objc private func didTapButton() { delegate.onClear() } - } extension DebugViewController: IDebugView { - func set(logs: [String]) { - DispatchQueue.main.async { //need to handle weird behaviour of large title in relation to UITextView + DispatchQueue.main.async { // need to handle weird behaviour of large title in relation to UITextView self.textView.text = logs.joined(separator: "\n") } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/DoubleSpendInfo/DoubleSpendInfoViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/DoubleSpendInfo/DoubleSpendInfoViewController.swift index 49fcbc5dd0..70a2b7dd0a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/DoubleSpendInfo/DoubleSpendInfoViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/DoubleSpendInfo/DoubleSpendInfoViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit +import ComponentKit import SectionsTableView +import SnapKit import ThemeKit -import ComponentKit +import UIKit class DoubleSpendInfoViewController: ThemeViewController { private let transactionHash: String @@ -17,7 +17,8 @@ class DoubleSpendInfoViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -43,66 +44,63 @@ class DoubleSpendInfoViewController: ThemeViewController { @objc private func onClose() { dismiss(animated: true) } - } extension DoubleSpendInfoViewController: SectionsDataSource { - private func row(id: String, title: String, value: String, isFirst: Bool, isLast: Bool) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = title - }, - .secondaryButton { component in - component.button.set(style: .default) - component.button.setTitle(value.shortened, for: .normal) - component.onTap = { - CopyHelper.copyAndNotify(value: value) - } + rootElement: .hStack([ + .text { component in + component.font = .subhead2 + component.textColor = .themeGray + component.text = title + }, + .secondaryButton { component in + component.button.set(style: .default) + component.button.setTitle(value.shortened, for: .normal) + component.onTap = { + CopyHelper.copyAndNotify(value: value) } - ]), - tableView: tableView, - id: id, - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) - } + }, + ]), + tableView: tableView, + id: id, + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) + } ) } func buildSections() -> [SectionProtocol] { [ Section( - id: "alert", - rows: [ - tableView.highlightedDescriptionRow(id: "alert", text: "double_spend_info.header".localized) - ] + id: "alert", + rows: [ + tableView.highlightedDescriptionRow(id: "alert", text: "double_spend_info.header".localized), + ] ), Section( - id: "hashes", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - row( - id: "tx-hash", - title: "double_spend_info.this_hash".localized, - value: transactionHash, - isFirst: true, - isLast: false - ), - row( - id: "conflicting-tx-hash", - title: "double_spend_info.conflicting_hash".localized, - value: conflictingTransactionHash, - isFirst: false, - isLast: true - ) - ] - ) + id: "hashes", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + row( + id: "tx-hash", + title: "double_spend_info.this_hash".localized, + value: transactionHash, + isFirst: true, + isLast: false + ), + row( + id: "conflicting-tx-hash", + title: "double_spend_info.conflicting_hash".localized, + value: conflictingTransactionHash, + isFirst: false, + isLast: true + ), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceModule.swift index ed0a33d898..33dedea1c2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceModule.swift @@ -1,10 +1,9 @@ import Foundation -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit struct AddEvmSyncSourceModule { - static func viewController(blockchainType: BlockchainType) -> UIViewController { let service = AddEvmSyncSourceService(blockchainType: blockchainType, evmSyncSourceManager: App.shared.evmSyncSourceManager) let viewModel = AddEvmSyncSourceViewModel(service: service) @@ -12,5 +11,4 @@ struct AddEvmSyncSourceModule { return ThemeNavigationController(rootViewController: viewController) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceService.swift index 0bc5ceca13..2cb5839597 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceService.swift @@ -1,8 +1,8 @@ -import Foundation -import RxSwift -import RxRelay import EvmKit +import Foundation import MarketKit +import RxRelay +import RxSwift class AddEvmSyncSourceService { private let blockchainType: BlockchainType @@ -16,11 +16,9 @@ class AddEvmSyncSourceService { self.blockchainType = blockchainType self.evmSyncSourceManager = evmSyncSourceManager } - } extension AddEvmSyncSourceService { - func set(urlString: String) { self.urlString = urlString.trimmingCharacters(in: .whitespacesAndNewlines) } @@ -48,14 +46,11 @@ extension AddEvmSyncSourceService { evmSyncSourceManager.saveSyncSource(blockchainType: blockchainType, url: url, auth: auth) } - } extension AddEvmSyncSourceService { - enum UrlError: Error { case invalid case alreadyExists } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewController.swift index 20a3237c7c..465b87dfcd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewController.swift @@ -1,12 +1,12 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift import RxCocoa -import ComponentKit +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit import UIExtensions +import UIKit class AddEvmSyncSourceViewController: KeyboardAwareViewController { private let viewModel: AddEvmSyncSourceViewModel @@ -28,7 +28,8 @@ class AddEvmSyncSourceViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -97,53 +98,50 @@ class AddEvmSyncSourceViewController: KeyboardAwareViewController { self.tableView.endUpdates() } } - } extension AddEvmSyncSourceViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "margin", - headerState: .margin(height: .margin12) + id: "margin", + headerState: .margin(height: .margin12) ), Section( - id: "url", - headerState: tableView.sectionHeader(text: "add_evm_sync_source.rpc_url".localized), - footerState: .margin(height: .margin24), - rows: [ - StaticRow( - cell: urlCell, - id: "url", - dynamicHeight: { [weak self] width in - self?.urlCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: urlCautionCell, - id: "url-caution", - dynamicHeight: { [weak self] width in - self?.urlCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "url", + headerState: tableView.sectionHeader(text: "add_evm_sync_source.rpc_url".localized), + footerState: .margin(height: .margin24), + rows: [ + StaticRow( + cell: urlCell, + id: "url", + dynamicHeight: { [weak self] width in + self?.urlCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: urlCautionCell, + id: "url-caution", + dynamicHeight: { [weak self] width in + self?.urlCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "basic-auth", - headerState: tableView.sectionHeader(text: "add_evm_sync_source.basic_auth".localized), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: basicAuthCell, - id: "basic-auth", - dynamicHeight: { [weak self] width in - self?.basicAuthCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + id: "basic-auth", + headerState: tableView.sectionHeader(text: "add_evm_sync_source.basic_auth".localized), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: basicAuthCell, + id: "basic-auth", + dynamicHeight: { [weak self] width in + self?.basicAuthCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewModel.swift index e43e8fbe98..ee19d20346 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/AddEvmSyncSource/AddEvmSyncSourceViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class AddEvmSyncSourceViewModel { private let service: AddEvmSyncSourceService @@ -12,11 +12,9 @@ class AddEvmSyncSourceViewModel { init(service: AddEvmSyncSourceService) { self.service = service } - } extension AddEvmSyncSourceViewModel { - var urlCautionDriver: Driver { urlCautionRelay.asDriver() } @@ -42,8 +40,6 @@ extension AddEvmSyncSourceViewModel { urlCautionRelay.accept(Caution(text: "add_evm_sync_source.warning.url_exists".localized, type: .warning)) } catch AddEvmSyncSourceService.UrlError.invalid { urlCautionRelay.accept(Caution(text: "add_evm_sync_source.error.invalid_url".localized, type: .error)) - } catch { - } + } catch {} } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkService.swift index d0992a03d1..c21880d581 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay import EvmKit import MarketKit +import RxRelay +import RxSwift class EvmNetworkService { let blockchain: Blockchain @@ -9,7 +9,7 @@ class EvmNetworkService { private var disposeBag = DisposeBag() private let stateRelay = PublishRelay() - private(set) var state: State = State(defaultItems: [], customItems: []) { + private(set) var state: State = .init(defaultItems: [], customItems: []) { didSet { stateRelay.accept(state) } @@ -30,8 +30,8 @@ class EvmNetworkService { private func syncState() { state = State( - defaultItems: items(syncSources: evmSyncSourceManager.defaultSyncSources(blockchainType: blockchain.type)), - customItems: items(syncSources: evmSyncSourceManager.customSyncSources(blockchainType: blockchain.type)) + defaultItems: items(syncSources: evmSyncSourceManager.defaultSyncSources(blockchainType: blockchain.type)), + customItems: items(syncSources: evmSyncSourceManager.customSyncSources(blockchainType: blockchain.type)) ) } @@ -40,8 +40,8 @@ class EvmNetworkService { return syncSources.map { syncSource in Item( - syncSource: syncSource, - selected: syncSource == currentSyncSource + syncSource: syncSource, + selected: syncSource == currentSyncSource ) } } @@ -55,11 +55,9 @@ class EvmNetworkService { syncState() } - } extension EvmNetworkService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -75,11 +73,9 @@ extension EvmNetworkService { func removeCustom(index: Int) { evmSyncSourceManager.delete(syncSource: state.customItems[index].syncSource, blockchainType: blockchain.type) } - } extension EvmNetworkService { - struct State { let defaultItems: [Item] let customItems: [Item] @@ -89,5 +85,4 @@ extension EvmNetworkService { let syncSource: EvmSyncSource let selected: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewController.swift index 769884ac18..d9599ab109 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewController.swift @@ -1,8 +1,8 @@ -import UIKit +import ComponentKit +import RxSwift import SectionsTableView import ThemeKit -import RxSwift -import ComponentKit +import UIKit class EvmNetworkViewController: ThemeViewController { private let viewModel: EvmNetworkViewModel @@ -23,7 +23,8 @@ class EvmNetworkViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -85,108 +86,105 @@ class EvmNetworkViewController: ThemeViewController { let module = AddEvmSyncSourceModule.viewController(blockchainType: viewModel.blockchainType) present(module, animated: true) } - } extension EvmNetworkViewController: SectionsDataSource { - private func customRowActions(index: Int) -> [RowAction] { [ RowAction( - pattern: .icon(image: UIImage(named: "circle_minus_shifted_24"), background: UIColor(red: 0, green: 0, blue: 0, alpha: 0)), - action: { [weak self] _ in - self?.viewModel.onRemoveCustom(index: index) - } - ) + pattern: .icon(image: UIImage(named: "circle_minus_shifted_24"), background: UIColor(red: 0, green: 0, blue: 0, alpha: 0)), + action: { [weak self] _ in + self?.viewModel.onRemoveCustom(index: index) + } + ), ] } - private func row(id: String, viewItem: EvmNetworkViewModel.ViewItem, rowActionProvider: (() -> [RowAction])? = nil, isFirst: Bool, isLast: Bool, action: @escaping () -> ()) -> RowProtocol { + private func row(id: String, viewItem: EvmNetworkViewModel.ViewItem, rowActionProvider: (() -> [RowAction])? = nil, isFirst: Bool, isLast: Bool, action: @escaping () -> Void) -> RowProtocol { tableView.universalRow62( - id: id, - title: .body(viewItem.name), - description: .subhead2(viewItem.url), - accessoryType: .check(viewItem.selected), - hash: "\(viewItem.selected)-\(isFirst)-\(isLast)", - autoDeselect: true, - rowActionProvider: rowActionProvider, - isFirst: isFirst, - isLast: isLast, - action: action + id: id, + title: .body(viewItem.name), + description: .subhead2(viewItem.url), + accessoryType: .check(viewItem.selected), + hash: "\(viewItem.selected)-\(isFirst)-\(isLast)", + autoDeselect: true, + rowActionProvider: rowActionProvider, + isFirst: isFirst, + isLast: isLast, + action: action ) } func buildSections() -> [SectionProtocol] { var sections: [SectionProtocol] = [ Section( - id: "description", - footerState: .margin(height: .margin24), - rows: [ - tableView.descriptionRow(id: "description-row", text: "evm_network.description".localized, font: .subhead2, textColor: .themeGray) - ] + id: "description", + footerState: .margin(height: .margin24), + rows: [ + tableView.descriptionRow(id: "description-row", text: "evm_network.description".localized, font: .subhead2, textColor: .themeGray), + ] ), Section( - id: "default", - footerState: .margin(height: customViewItems.isEmpty ? .margin32 : .margin24), - rows: defaultViewItems.enumerated().map { index, viewItem in - row( - id: "default-\(index)", - viewItem: viewItem, - isFirst: index == 0, - isLast: index == defaultViewItems.count - 1, - action: { [weak self] in - self?.viewModel.onSelectDefault(index: index) - } - ) - } - ) + id: "default", + footerState: .margin(height: customViewItems.isEmpty ? .margin32 : .margin24), + rows: defaultViewItems.enumerated().map { index, viewItem in + row( + id: "default-\(index)", + viewItem: viewItem, + isFirst: index == 0, + isLast: index == defaultViewItems.count - 1, + action: { [weak self] in + self?.viewModel.onSelectDefault(index: index) + } + ) + } + ), ] if !customViewItems.isEmpty { sections.append( - Section( - id: "custom", - headerState: tableView.sectionHeader(text: "evm_network.added".localized), - footerState: .margin(height: .margin32), - rows: customViewItems.enumerated().map { index, viewItem in - row( - id: "custom-\(index)", - viewItem: viewItem, - rowActionProvider: { [weak self] in - self?.customRowActions(index: index) ?? [] - }, - isFirst: index == 0, - isLast: index == customViewItems.count - 1, - action: { [weak self] in - self?.viewModel.onSelectCustom(index: index) - } - ) + Section( + id: "custom", + headerState: tableView.sectionHeader(text: "evm_network.added".localized), + footerState: .margin(height: .margin32), + rows: customViewItems.enumerated().map { index, viewItem in + row( + id: "custom-\(index)", + viewItem: viewItem, + rowActionProvider: { [weak self] in + self?.customRowActions(index: index) ?? [] + }, + isFirst: index == 0, + isLast: index == customViewItems.count - 1, + action: { [weak self] in + self?.viewModel.onSelectCustom(index: index) } - ) + ) + } + ) ) } sections.append( - Section( + Section( + id: "add-new", + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( id: "add-new", - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "add-new", - image: .local(UIImage(named: "plus_24")?.withTintColor(.themeJacob)), - title: .body("evm_network.add_new".localized, color: .themeJacob), - autoDeselect: true, - isFirst: true, - isLast: true, - action: { [weak self] in - self?.openAddNew() - } - ) - ] - ) + image: .local(UIImage(named: "plus_24")?.withTintColor(.themeJacob)), + title: .body("evm_network.add_new".localized, color: .themeJacob), + autoDeselect: true, + isFirst: true, + isLast: true, + action: { [weak self] in + self?.openAddNew() + } + ), + ] + ) ) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewModel.swift index 4b29654453..d136246e06 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmNetwork/EvmNetworkViewModel.swift @@ -1,16 +1,16 @@ -import Foundation -import RxSwift -import RxRelay -import RxCocoa import EvmKit +import Foundation import MarketKit +import RxCocoa +import RxRelay +import RxSwift class EvmNetworkViewModel { private let service: EvmNetworkService private let disposeBag = DisposeBag() private let stateRelay = BehaviorRelay(value: State(defaultViewItems: [], customViewItems: [])) - private let finishRelay = PublishRelay<()>() + private let finishRelay = PublishRelay() init(service: EvmNetworkService) { self.service = service @@ -22,8 +22,8 @@ class EvmNetworkViewModel { private func sync(state: EvmNetworkService.State) { let state = State( - defaultViewItems: state.defaultItems.map { viewItem(item: $0) }, - customViewItems: state.customItems.map { viewItem(item: $0) } + defaultViewItems: state.defaultItems.map { viewItem(item: $0) }, + customViewItems: state.customItems.map { viewItem(item: $0) } ) stateRelay.accept(state) @@ -31,28 +31,26 @@ class EvmNetworkViewModel { private func viewItem(item: EvmNetworkService.Item) -> ViewItem { ViewItem( - name: item.syncSource.name, - url: url(rpcSource: item.syncSource.rpcSource)?.absoluteString, - selected: item.selected + name: item.syncSource.name, + url: url(rpcSource: item.syncSource.rpcSource)?.absoluteString, + selected: item.selected ) } private func url(rpcSource: RpcSource) -> URL? { switch rpcSource { - case .http(let urls, _): return urls.first - case .webSocket(let url, _): return url + case let .http(urls, _): return urls.first + case let .webSocket(url, _): return url } } - } extension EvmNetworkViewModel { - var stateDriver: Driver { stateRelay.asDriver() } - var finishSignal: Signal<()> { + var finishSignal: Signal { finishRelay.asSignal() } @@ -79,11 +77,9 @@ extension EvmNetworkViewModel { func onRemoveCustom(index: Int) { service.removeCustom(index: index) } - } extension EvmNetworkViewModel { - struct State { let defaultViewItems: [ViewItem] let customViewItems: [ViewItem] @@ -94,5 +90,4 @@ extension EvmNetworkViewModel { let url: String? let selected: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyModule.swift index 14d09542af..5ead5411f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyModule.swift @@ -1,8 +1,7 @@ -import UIKit import ThemeKit +import UIKit struct EvmPrivateKeyModule { - static func viewController(accountType: AccountType) -> UIViewController? { guard let service = EvmPrivateKeyService(accountType: accountType, evmBlockchainManager: App.shared.evmBlockchainManager) else { return nil @@ -11,5 +10,4 @@ struct EvmPrivateKeyModule { let viewModel = EvmPrivateKeyViewModel(service: service) return EvmPrivateKeyViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyService.swift index fedda7ad1b..1d8248be9d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyService.swift @@ -8,14 +8,14 @@ class EvmPrivateKeyService { switch accountType { case .mnemonic: guard let seed = accountType.mnemonicSeed, - let privateKey = try? Signer.privateKey(seed: seed, chain: evmBlockchainManager.chain(blockchainType: .ethereum)).hs.hex else { + let privateKey = try? Signer.privateKey(seed: seed, chain: evmBlockchainManager.chain(blockchainType: .ethereum)).hs.hex + else { return nil } self.privateKey = privateKey - case .evmPrivateKey(data: let data): + case let .evmPrivateKey(data: data): privateKey = data.hs.hex default: return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewController.swift index 03b7c15366..b57c6c7ce3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView import ComponentKit +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class EvmPrivateKeyViewController: ThemeViewController { private let viewModel: EvmPrivateKeyViewModel @@ -17,7 +17,8 @@ class EvmPrivateKeyViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -77,11 +78,9 @@ class EvmPrivateKeyViewController: ThemeViewController { visible = !visible tableView.reload() } - } extension EvmPrivateKeyViewController: SectionsDataSource { - private func marginRow(id: String, height: CGFloat) -> RowProtocol { Row(id: id, height: height) } @@ -95,46 +94,45 @@ extension EvmPrivateKeyViewController: SectionsDataSource { return [ Section( - id: "main", - footerState: .margin(height: .margin32), - rows: [ - tableView.highlightedDescriptionRow( - id: "warning", - text: "recovery_phrase.warning".localized(AppConfig.appName) - ), - marginRow(id: "warning-bottom-margin", height: .margin12), - CellBuilderNew.row( - rootElement: .text { component in - component.font = visible ? textFont : .subhead2 - component.textColor = visible ? .themeLeah : .themeGray - component.text = visible ? privateKey : "evm_private_key.tap_to_show".localized - component.textAlignment = visible ? .left : .center - component.numberOfLines = 0 - }, - layoutMargins: UIEdgeInsets(top: 0, left: .margin24, bottom: 0, right: .margin24), - tableView: tableView, - id: "private-key", - dynamicHeight: { width in - CellBuilderNew.height( - containerWidth: width, - backgroundStyle: backgroundStyle, - text: privateKey, - font: textFont, - verticalPadding: .margin24, - elements: [.multiline] - ) - }, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, cornerRadius: .cornerRadius24, isFirst: true, isLast: true) - cell.selectionStyle = .none - }, - action: { [weak self] in - self?.toggle() - } - ) - ] - ) + id: "main", + footerState: .margin(height: .margin32), + rows: [ + tableView.highlightedDescriptionRow( + id: "warning", + text: "recovery_phrase.warning".localized(AppConfig.appName) + ), + marginRow(id: "warning-bottom-margin", height: .margin12), + CellBuilderNew.row( + rootElement: .text { component in + component.font = visible ? textFont : .subhead2 + component.textColor = visible ? .themeLeah : .themeGray + component.text = visible ? privateKey : "evm_private_key.tap_to_show".localized + component.textAlignment = visible ? .left : .center + component.numberOfLines = 0 + }, + layoutMargins: UIEdgeInsets(top: 0, left: .margin24, bottom: 0, right: .margin24), + tableView: tableView, + id: "private-key", + dynamicHeight: { width in + CellBuilderNew.height( + containerWidth: width, + backgroundStyle: backgroundStyle, + text: privateKey, + font: textFont, + verticalPadding: .margin24, + elements: [.multiline] + ) + }, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, cornerRadius: .cornerRadius24, isFirst: true, isLast: true) + cell.selectionStyle = .none + }, + action: { [weak self] in + self?.toggle() + } + ), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewModel.swift index ac0394d640..36accb79f4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmPrivateKey/EvmPrivateKeyViewModel.swift @@ -4,13 +4,10 @@ class EvmPrivateKeyViewModel { init(service: EvmPrivateKeyService) { self.service = service } - } extension EvmPrivateKeyViewModel { - var privateKey: String { service.privateKey } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsModule.swift index d4694ffbde..71352f3440 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsModule.swift @@ -1,20 +1,20 @@ +import EvmKit +import MarketKit import SectionsTableView -import UIKit import ThemeKit -import MarketKit -import EvmKit +import UIKit struct EvmSendSettingsModule { - static func instance(evmKit: EvmKit.Kit, blockchainType: BlockchainType, sendData: SendEvmData, coinServiceFactory: EvmCoinServiceFactory, gasPrice: GasPrice? = nil, previousTransaction: EvmKit.Transaction? = nil, - predefinedGasLimit: Int? = nil, predefinedNonce: Int? = nil) -> (EvmSendSettingsService, EvmSendSettingsViewModel)? { + predefinedGasLimit: Int? = nil, predefinedNonce: Int? = nil) -> (EvmSendSettingsService, EvmSendSettingsViewModel)? + { let gasPriceService = EvmFeeModule.gasPriceService(evmKit: evmKit, gasPrice: gasPrice, previousTransaction: previousTransaction) let gasDataService = EvmCommonGasDataService.instance( - evmKit: evmKit, - blockchainType: blockchainType, - predefinedGasLimit: predefinedGasLimit + evmKit: evmKit, + blockchainType: blockchainType, + predefinedGasLimit: predefinedGasLimit ) let coinService = coinServiceFactory.baseCoinService @@ -61,13 +61,12 @@ struct EvmSendSettingsModule { return ThemeNavigationController(rootViewController: settingsViewController) } - } protocol IEvmSendSettingsDataSource: AnyObject { var tableView: SectionsTableView? { get set } - var onOpenInfo: ((String, String) -> ())? { get set } - var onUpdateAlteredState: (() -> ())? { get set } + var onOpenInfo: ((String, String) -> Void)? { get set } + var onUpdateAlteredState: (() -> Void)? { get set } var altered: Bool { get } var buildSections: [SectionProtocol] { get } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsService.swift index 2aa4f301c8..b06c889988 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsService.swift @@ -30,44 +30,40 @@ class EvmSendSettingsService { switch (feeService.status, nonceService.status) { case (.loading, _), (_, .loading): status = .loading - case (.failed(let error), _), (_, .failed(let error)): + case let (.failed(error), _), let (_, .failed(error)): status = .failed(error) default: - guard case .completed(let fallibleTransaction) = feeService.status else { + guard case let .completed(fallibleTransaction) = feeService.status else { return } - guard case .completed(let fallibleNonce) = nonceService.status else { + guard case let .completed(fallibleNonce) = nonceService.status else { return } status = .completed(FallibleData( - data: Transaction( - transactionData: fallibleTransaction.data.transactionData, - gasData: fallibleTransaction.data.gasData, - nonce: fallibleNonce.data - ), - errors: fallibleTransaction.errors + fallibleNonce.errors, warnings: fallibleTransaction.warnings) + data: Transaction( + transactionData: fallibleTransaction.data.transactionData, + gasData: fallibleTransaction.data.gasData, + nonce: fallibleNonce.data + ), + errors: fallibleTransaction.errors + fallibleNonce.errors, warnings: fallibleTransaction.warnings + ) ) } } - } extension EvmSendSettingsService { - var statusObservable: Observable>> { statusRelay.asObservable() } - } extension EvmSendSettingsService { - struct Transaction { let transactionData: TransactionData let gasData: EvmFeeModule.GasData let nonce: Int } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewController.swift index dadf254116..ce5d4b0d9b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class EvmSendSettingsViewController: ThemeViewController { private let disposeBag = DisposeBag() @@ -46,7 +46,8 @@ class EvmSendSettingsViewController: ThemeViewController { navigationItem.leftBarButtonItem?.isEnabled = false } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -96,7 +97,7 @@ class EvmSendSettingsViewController: ThemeViewController { private func handle(caution: TitledCaution?) { cautionCell.isVisible = caution != nil - if let caution = caution { + if let caution { cautionCell.bind(caution: caution) } @@ -107,31 +108,28 @@ class EvmSendSettingsViewController: ThemeViewController { } } } - } extension EvmSendSettingsViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { - let dataSourceSections = dataSources.map{ $0.buildSections }.reduce([], +) + let dataSourceSections = dataSources.map(\.buildSections).reduce([], +) let cautionsSections: [SectionProtocol] = [ Section( - id: "caution", - headerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: cautionCell, - id: "caution", - dynamicHeight: { [weak self] containerWidth in - self?.cautionCell.cellHeight(containerWidth: containerWidth) ?? 0 - } - ) - ] - ) + id: "caution", + headerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: cautionCell, + id: "caution", + dynamicHeight: { [weak self] containerWidth in + self?.cautionCell.cellHeight(containerWidth: containerWidth) ?? 0 + } + ), + ] + ), ] return dataSourceSections + cautionsSections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewModel.swift index dda366c016..7ef1fe57ce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/EvmSendSettingsViewModel.swift @@ -1,5 +1,5 @@ -import RxSwift import RxCocoa +import RxSwift class EvmSendSettingsViewModel { let service: EvmSendSettingsService @@ -29,21 +29,18 @@ class EvmSendSettingsViewModel { switch transactionStatus { case .loading: cautions = [] - case .failed(let error): + case let .failed(error): cautions = cautionsFactory.items(errors: [error], warnings: [], baseCoinService: coinService) - case .completed(let fallibleTransaction): + case let .completed(fallibleTransaction): cautions = cautionsFactory.items(errors: fallibleTransaction.errors, warnings: fallibleTransaction.warnings, baseCoinService: coinService) } cautionRelay.accept(cautions.first) } - } extension EvmSendSettingsViewModel { - var cautionDriver: Driver { cautionRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeDataSource.swift index 3301b90447..aef14247fd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeDataSource.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class Eip1559EvmFeeDataSource { private let viewModel: Eip1559EvmFeeViewModel @@ -17,8 +17,8 @@ class Eip1559EvmFeeDataSource { private var tipsCell = StepperAmountInputCell(allowFractionalNumbers: true) weak var tableView: SectionsTableView? - var onOpenInfo: ((String, String) -> ())? = nil - var onUpdateAlteredState: (() -> ())? = nil + var onOpenInfo: ((String, String) -> Void)? + var onUpdateAlteredState: (() -> Void)? init(viewModel: Eip1559EvmFeeViewModel) { self.viewModel = viewModel @@ -26,7 +26,8 @@ class Eip1559EvmFeeDataSource { feeCell = FeeCell(viewModel: viewModel, title: "fee_settings.network_fee".localized) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -57,106 +58,103 @@ class Eip1559EvmFeeDataSource { private func syncGasLimitCell(value: String? = nil) { CellBuilderNew.buildStatic( - cell: gasLimitCell, - rootElement: .hStack([ - .secondaryButton { [weak self] component in - component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) - component.button.setTitle("fee_settings.gas_limit".localized, for: .normal) - component.onTap = { - self?.onOpenInfo?("fee_settings.gas_limit".localized, "fee_settings.gas_limit.info".localized) - } - }, - .textElement(text: .subhead1(value), parameters: [.rightAlignment]) - ]) + cell: gasLimitCell, + rootElement: .hStack([ + .secondaryButton { [weak self] component in + component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) + component.button.setTitle("fee_settings.gas_limit".localized, for: .normal) + component.onTap = { + self?.onOpenInfo?("fee_settings.gas_limit".localized, "fee_settings.gas_limit.info".localized) + } + }, + .textElement(text: .subhead1(value), parameters: [.rightAlignment]), + ]) ) } private func syncBaseFeeCell(value: String? = nil) { CellBuilderNew.buildStatic( - cell: baseFeeCell, - rootElement: .hStack([ - .secondaryButton { [weak self] component in - component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) - component.button.setTitle("fee_settings.base_fee".localized, for: .normal) - component.onTap = { - self?.onOpenInfo?("fee_settings.base_fee".localized, "fee_settings.base_fee.info".localized) - } - }, - .textElement(text: .subhead1(value), parameters: [.rightAlignment]) - ]) + cell: baseFeeCell, + rootElement: .hStack([ + .secondaryButton { [weak self] component in + component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) + component.button.setTitle("fee_settings.base_fee".localized, for: .normal) + component.onTap = { + self?.onOpenInfo?("fee_settings.base_fee".localized, "fee_settings.base_fee.info".localized) + } + }, + .textElement(text: .subhead1(value), parameters: [.rightAlignment]), + ]) ) } - } extension Eip1559EvmFeeDataSource: IEvmSendSettingsDataSource { - var altered: Bool { viewModel.altered } var buildSections: [SectionProtocol] { - guard let tableView = tableView else { + guard let tableView else { return [] } let feeSections: [SectionProtocol] = [ Section( - id: "fee", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCell, - id: "fee", - height: .heightDoubleLineCell - ), - StaticRow( - cell: gasLimitCell, - id: "gas-limit", - height: .heightCell48 - ), - StaticRow( - cell: baseFeeCell, - id: "base-fee", - height: .heightCell48 - - ) - ] - ) + id: "fee", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCell, + id: "fee", + height: .heightDoubleLineCell + ), + StaticRow( + cell: gasLimitCell, + id: "gas-limit", + height: .heightCell48 + ), + StaticRow( + cell: baseFeeCell, + id: "base-fee", + height: .heightCell48 + ), + ] + ), ] let maxGasPriceSections: [SectionProtocol] = [ Section( - id: "max-gas-price", - headerState: .margin(height: .margin24), - rows: [ - tableView.subtitleWithInfoButtonRow(text: "fee_settings.max_fee_rate".localized + " (Gwei)", uppercase: false) { [weak self] in - self?.onOpenInfo?("fee_settings.max_fee_rate".localized, "fee_settings.max_fee_rate.info".localized) - }, - StaticRow( - cell: maxGasPriceCell, - id: "max-gas-price", - height: .heightCell48 - ) - ] - ) + id: "max-gas-price", + headerState: .margin(height: .margin24), + rows: [ + tableView.subtitleWithInfoButtonRow(text: "fee_settings.max_fee_rate".localized + " (Gwei)", uppercase: false) { [weak self] in + self?.onOpenInfo?("fee_settings.max_fee_rate".localized, "fee_settings.max_fee_rate.info".localized) + }, + StaticRow( + cell: maxGasPriceCell, + id: "max-gas-price", + height: .heightCell48 + ), + ] + ), ] let tipsSections: [SectionProtocol] = [ Section( - id: "tips", - headerState: .margin(height: .margin24), - rows: [ - tableView.subtitleWithInfoButtonRow(text: "fee_settings.tips".localized + " (Gwei)", uppercase: false) { [weak self] in - self?.onOpenInfo?("fee_settings.tips".localized, "fee_settings.tips.info".localized) - }, - StaticRow( - cell: tipsCell, - id: "tips", - height: .heightCell48 - ) - ] - ) + id: "tips", + headerState: .margin(height: .margin24), + rows: [ + tableView.subtitleWithInfoButtonRow(text: "fee_settings.tips".localized + " (Gwei)", uppercase: false) { [weak self] in + self?.onOpenInfo?("fee_settings.tips".localized, "fee_settings.tips.info".localized) + }, + StaticRow( + cell: tipsCell, + id: "tips", + height: .heightCell48 + ), + ] + ), ] return feeSections + maxGasPriceSections + tipsSections @@ -165,5 +163,4 @@ extension Eip1559EvmFeeDataSource: IEvmSendSettingsDataSource { func onTapReset() { viewModel.reset() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeViewModel.swift index 1e55e236f7..7ac84af46d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559EvmFeeViewModel.swift @@ -62,7 +62,7 @@ class Eip1559EvmFeeViewModel { spinnerVisible = true feeValue = nil gasLimit = "n/a".localized - case .failed(_): + case .failed: spinnerVisible = false feeValue = .error(text: "n/a".localized) gasLimit = "n/a".localized @@ -74,8 +74,8 @@ class Eip1559EvmFeeViewModel { let tilda = gasData.isSurcharged if fallibleTransaction.errors.isEmpty, let coinValue = amountData.coinValue.formattedFull { feeValue = .regular( - text: "\(tilda ? "~" : "")\(coinValue)", - secondaryText: amountData.currencyValue?.formattedFull.map { "\(tilda ? "~" : "")\($0)" } + text: "\(tilda ? "~" : "")\(coinValue)", + secondaryText: amountData.currencyValue?.formattedFull.map { "\(tilda ? "~" : "")\($0)" } ) } else { feeValue = .error(text: "n/a".localized) @@ -100,11 +100,11 @@ class Eip1559EvmFeeViewModel { cautionType = nil maxGasPrice = nil tips = nil - case .failed(_): + case .failed: cautionType = .error maxGasPrice = nil tips = nil - case .completed(let fallibleGasPrice): + case let .completed(fallibleGasPrice): maxGasPrice = feeViewItemFactory.decimalValue(value: gasPriceService.maxFee) tips = feeViewItemFactory.decimalValue(value: gasPriceService.tips) cautionType = fallibleGasPrice.cautionType @@ -120,14 +120,12 @@ class Eip1559EvmFeeViewModel { currentBaseFeeRelay.accept(feeViewItemFactory.description(value: recommendedBaseFee, step: baseStep)) } - private func sync(usingRecommended: Bool) { - alteredStateRelay.accept(Void()) + private func sync(usingRecommended _: Bool) { + alteredStateRelay.accept(()) } - } extension Eip1559EvmFeeViewModel { - var altered: Bool { !gasPriceService.usingRecommended } @@ -167,11 +165,9 @@ extension Eip1559EvmFeeViewModel { var cautionTypeDriver: Driver { cautionTypeRelay.asDriver() } - } extension Eip1559EvmFeeViewModel: IFeeViewModel { - var valueDriver: Driver { valueRelay.asDriver() } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559GasPriceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559GasPriceService.swift index e7531cec05..03f2bf0394 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559GasPriceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Eip1559/Eip1559GasPriceService.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation import RxRelay import RxSwift @@ -100,9 +100,7 @@ class Eip1559GasPriceService { } private func handle(feeHistory: FeeHistory) { - let tipsConsidered = feeHistory.reward.compactMap { - $0.first - } + let tipsConsidered = feeHistory.reward.compactMap(\.first) let baseFeesConsidered = feeHistory.baseFeePerGas.suffix(2) guard !baseFeesConsidered.isEmpty, !tipsConsidered.isEmpty else { @@ -111,12 +109,12 @@ class Eip1559GasPriceService { } recommendedTips = tipsConsidered.reduce(0, +) / tipsConsidered.count - if let minRecommendedTips = minRecommendedTips { + if let minRecommendedTips { recommendedTips = max(recommendedTips, minRecommendedTips) } recommendedMaxFee = baseFeesConsidered.max() ?? 0 + recommendedTips - if let minRecommendedMaxFee = minRecommendedMaxFee { + if let minRecommendedMaxFee { recommendedMaxFee = max(recommendedMaxFee, minRecommendedMaxFee) } @@ -170,5 +168,4 @@ extension Eip1559GasPriceService { usingRecommended = true sync() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmCommonGasDataService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmCommonGasDataService.swift index b612d14e64..298ea7088e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmCommonGasDataService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmCommonGasDataService.swift @@ -24,21 +24,19 @@ class EvmCommonGasDataService { let adjustedTransactionData = stubAmount.map { TransactionData(to: transactionData.to, value: $0, input: transactionData.input) } ?? transactionData return evmKit.estimateGas(transactionData: adjustedTransactionData, gasPrice: gasPrice) - .map { estimatedGasLimit in - let limit = surchargeRequired ? EvmFeeModule.surcharged(gasLimit: estimatedGasLimit) : estimatedGasLimit - - return EvmFeeModule.GasData( - limit: limit, - estimatedLimit: estimatedGasLimit, - price: gasPrice - ) - } + .map { estimatedGasLimit in + let limit = surchargeRequired ? EvmFeeModule.surcharged(gasLimit: estimatedGasLimit) : estimatedGasLimit + + return EvmFeeModule.GasData( + limit: limit, + estimatedLimit: estimatedGasLimit, + price: gasPrice + ) + } } - } extension EvmCommonGasDataService { - static func instance(evmKit: EvmKit.Kit, blockchainType: BlockchainType, predefinedGasLimit: Int?) -> EvmCommonGasDataService { if let rollupFeeContractAddress = blockchainType.rollupFeeContractAddress { return EvmRollupGasDataService(evmKit: evmKit, l1GasFeeContractAddress: rollupFeeContractAddress, predefinedGasLimit: predefinedGasLimit) @@ -46,5 +44,4 @@ extension EvmCommonGasDataService { return EvmCommonGasDataService(evmKit: evmKit, predefinedGasLimit: predefinedGasLimit) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeModule.swift index 7c918744cd..fcf4f43bb7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeModule.swift @@ -1,9 +1,9 @@ -import UIKit import BigInt import EvmKit -import RxSwift import RxCocoa +import RxSwift import ThemeKit +import UIKit struct EvmFeeModule { private static let surchargePercent: Double = 10 @@ -19,7 +19,7 @@ struct EvmFeeModule { var minRecommendedMaxFee: Int? = nil var minRecommendedTips: Int? = nil - if case .eip1559(let maxBaseFee, let maxTips) = gasPrice { + if case let .eip1559(maxBaseFee, maxTips) = gasPrice { initialMaxBaseFee = maxBaseFee initialMaxTips = maxTips } @@ -34,7 +34,7 @@ struct EvmFeeModule { var initialGasPrice: Int? = nil var minRecommendedGasPrice: Int? = nil - if case .legacy(let gasPrice) = gasPrice { + if case let .legacy(gasPrice) = gasPrice { initialGasPrice = gasPrice } @@ -48,7 +48,6 @@ struct EvmFeeModule { } extension EvmFeeModule { - enum GasDataError: Error { case insufficientBalance } @@ -120,7 +119,6 @@ extension EvmFeeModule { let transactionData: TransactionData let gasData: GasData } - } protocol IEvmFeeService { @@ -156,25 +154,24 @@ struct RangeBounds { var upperBound = 0 switch lower { - case .factor(let factor): lowerBound = Int(Float(center) * factor) - case .distance(let distance): lowerBound = center - distance - case .fixed(let value): lowerBound = value + case let .factor(factor): lowerBound = Int(Float(center) * factor) + case let .distance(distance): lowerBound = center - distance + case let .fixed(value): lowerBound = value } lowerBound = max(lowerBound, 0) switch upper { - case .factor(let factor): upperBound = Int(Float(center) * factor) - case .distance(let distance): upperBound = center + distance - case .fixed(let value): upperBound = value + case let .factor(factor): upperBound = Int(Float(center) * factor) + case let .distance(distance): upperBound = center + distance + case let .fixed(value): upperBound = value } - if let selected = selected { + if let selected { lowerBound = min(lowerBound, selected) upperBound = max(upperBound, selected) } - return lowerBound...upperBound + return lowerBound ... upperBound } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeService.swift index 8f0f4d580b..955c9c7503 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeService.swift @@ -51,45 +51,46 @@ class EvmFeeService { if transactionData.input.isEmpty, transactionData.value == evmBalance { // If try to send native token (input is empty) and max value, we must calculate fee and decrease maximum value by that fee single = gasDataService - .gasDataSingle(gasPrice: fallibleGasPrices.data.recommended, transactionData: transactionData, stubAmount: 1) - .flatMap { adjustedGasData in - adjustedGasData.set(price: fallibleGasPrices.data.userDefined) - - if transactionData.value <= adjustedGasData.fee { - return Single.error(EvmFeeModule.GasDataError.insufficientBalance) - } else { - let adjustedTransactionData = TransactionData(to: transactionData.to, value: transactionData.value - adjustedGasData.fee, input: transactionData.input) - return Single.just(EvmFeeModule.Transaction(transactionData: adjustedTransactionData, gasData: adjustedGasData)) - } + .gasDataSingle(gasPrice: fallibleGasPrices.data.recommended, transactionData: transactionData, stubAmount: 1) + .flatMap { adjustedGasData in + adjustedGasData.set(price: fallibleGasPrices.data.userDefined) + + if transactionData.value <= adjustedGasData.fee { + return Single.error(EvmFeeModule.GasDataError.insufficientBalance) + } else { + let adjustedTransactionData = TransactionData(to: transactionData.to, value: transactionData.value - adjustedGasData.fee, input: transactionData.input) + return Single.just(EvmFeeModule.Transaction(transactionData: adjustedTransactionData, gasData: adjustedGasData)) } + } } else { single = gasDataService - .gasDataSingle(gasPrice: fallibleGasPrices.data.userDefined, transactionData: transactionData) - .catchError { [weak self] error in - if case AppError.ethereum(reason: let ethereumError) = error.convertedError, - case .lowerThanBaseGasLimit = ethereumError, - let _self = self { - return _self - .gasDataService - .gasDataSingle(gasPrice: fallibleGasPrices.data.recommended, transactionData: transactionData) - .map { gasData in - gasData.set(price: fallibleGasPrices.data.userDefined) - return gasData - } - } - - return .error(error) + .gasDataSingle(gasPrice: fallibleGasPrices.data.userDefined, transactionData: transactionData) + .catchError { [weak self] error in + if case let AppError.ethereum(reason: ethereumError) = error.convertedError, + case .lowerThanBaseGasLimit = ethereumError, + let _self = self + { + return _self + .gasDataService + .gasDataSingle(gasPrice: fallibleGasPrices.data.recommended, transactionData: transactionData) + .map { gasData in + gasData.set(price: fallibleGasPrices.data.userDefined) + return gasData + } } - .map { EvmFeeModule.Transaction(transactionData: transactionData, gasData: $0) } + + return .error(error) + } + .map { EvmFeeModule.Transaction(transactionData: transactionData, gasData: $0) } } single.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] transaction in - self?.syncStatus(transaction: transaction, errors: fallibleGasPrices.errors, warnings: fallibleGasPrices.warnings) - }, onError: { error in - self.status = .failed(error) - }) - .disposed(by: disposeBag) + .subscribe(onSuccess: { [weak self] transaction in + self?.syncStatus(transaction: transaction, errors: fallibleGasPrices.errors, warnings: fallibleGasPrices.warnings) + }, onError: { error in + self.status = .failed(error) + }) + .disposed(by: disposeBag) } private var evmBalance: BigUInt { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeViewItemFactory.swift index 4567be5f82..59302d00c8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmFeeViewItemFactory.swift @@ -50,5 +50,4 @@ extension FeeViewItemFactory { func intValue(value: Float) -> Int { Int(value * Float(scale.scaleValue)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmRollupGasDataService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmRollupGasDataService.swift index fb2baa5084..4ee15a5fe7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmRollupGasDataService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/EvmRollupGasDataService.swift @@ -41,10 +41,9 @@ class EvmRollupGasDataService: EvmCommonGasDataService { } return self?.l1GasFeeSingle(transactionData: l1TransactionData, gasPrice: gasPrice, gasLimit: commonGasData.limit) - .map { l1GasFee in - EvmFeeModule.RollupGasData(additionalFee: l1GasFee, limit: commonGasData.limit, price: gasPrice) - } ?? .just(EvmFeeModule.RollupGasData(additionalFee: 0, limit: commonGasData.limit, price: gasPrice)) + .map { l1GasFee in + EvmFeeModule.RollupGasData(additionalFee: l1GasFee, limit: commonGasData.limit, price: gasPrice) + } ?? .just(EvmFeeModule.RollupGasData(additionalFee: 0, limit: commonGasData.limit, price: gasPrice)) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeDataSource.swift index 9355297649..3c9867e188 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeDataSource.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class LegacyEvmFeeDataSource { private let viewModel: LegacyEvmFeeViewModel @@ -15,8 +15,8 @@ class LegacyEvmFeeDataSource { private var gasPriceCell = StepperAmountInputCell(allowFractionalNumbers: true) weak var tableView: SectionsTableView? - var onOpenInfo: ((String, String) -> ())? = nil - var onUpdateAlteredState: (() -> ())? = nil + var onOpenInfo: ((String, String) -> Void)? + var onUpdateAlteredState: (() -> Void)? init(viewModel: LegacyEvmFeeViewModel) { self.viewModel = viewModel @@ -43,67 +43,65 @@ class LegacyEvmFeeDataSource { private func syncGasLimitCell(value: String? = nil) { CellBuilderNew.buildStatic( - cell: gasLimitCell, - rootElement: .hStack([ - .secondaryButton { [weak self] component in - component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) - component.button.setTitle("fee_settings.gas_limit".localized, for: .normal) - component.onTap = { - self?.onOpenInfo?("fee_settings.gas_limit".localized, "fee_settings.gas_limit.info".localized) - } - }, - .textElement(text: .subhead1(value), parameters: [.rightAlignment]) - ]) + cell: gasLimitCell, + rootElement: .hStack([ + .secondaryButton { [weak self] component in + component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) + component.button.setTitle("fee_settings.gas_limit".localized, for: .normal) + component.onTap = { + self?.onOpenInfo?("fee_settings.gas_limit".localized, "fee_settings.gas_limit.info".localized) + } + }, + .textElement(text: .subhead1(value), parameters: [.rightAlignment]), + ]) ) } - } extension LegacyEvmFeeDataSource: IEvmSendSettingsDataSource { - var altered: Bool { viewModel.altered } var buildSections: [SectionProtocol] { - guard let tableView = tableView else { + guard let tableView else { return [] } let feeSections: [SectionProtocol] = [ Section( - id: "fee", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCell, - id: "fee", - height: .heightDoubleLineCell - ), - StaticRow( - cell: gasLimitCell, - id: "gas-limit", - height: .heightCell48 - ) - ] - ) + id: "fee", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCell, + id: "fee", + height: .heightDoubleLineCell + ), + StaticRow( + cell: gasLimitCell, + id: "gas-limit", + height: .heightCell48 + ), + ] + ), ] let gasDataSections: [SectionProtocol] = [ Section( - id: "gas-price", - headerState: .margin(height: .margin24), - rows: [ - tableView.subtitleWithInfoButtonRow(text: "fee_settings.gas_price".localized + " (Gwei)", uppercase: false) { [weak self] in - self?.onOpenInfo?("fee_settings.gas_price".localized, "fee_settings.gas_price.info".localized) - }, - StaticRow( - cell: gasPriceCell, - id: "gas-price", - height: .heightCell48 - ) - ] - ) + id: "gas-price", + headerState: .margin(height: .margin24), + rows: [ + tableView.subtitleWithInfoButtonRow(text: "fee_settings.gas_price".localized + " (Gwei)", uppercase: false) { [weak self] in + self?.onOpenInfo?("fee_settings.gas_price".localized, "fee_settings.gas_price.info".localized) + }, + StaticRow( + cell: gasPriceCell, + id: "gas-price", + height: .heightCell48 + ), + ] + ), ] return feeSections + gasDataSections @@ -112,5 +110,4 @@ extension LegacyEvmFeeDataSource: IEvmSendSettingsDataSource { func onTapReset() { viewModel.reset() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeViewModel.swift index e8c7770f4e..89019d7e8e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyEvmFeeViewModel.swift @@ -1,8 +1,8 @@ +import EvmKit import Foundation -import RxSwift import RxCocoa import RxRelay -import EvmKit +import RxSwift class LegacyEvmFeeViewModel { private let disposeBag = DisposeBag() @@ -43,11 +43,11 @@ class LegacyEvmFeeViewModel { case .loading: cautionType = nil gasPrice = nil - case .failed(_): + case .failed: cautionType = .error gasPrice = nil - case .completed(let fallibleGasPrice): - if case .legacy(let _gasPrice) = fallibleGasPrice.data.userDefined { + case let .completed(fallibleGasPrice): + if case let .legacy(_gasPrice) = fallibleGasPrice.data.userDefined { gasPrice = feeViewItemFactory.decimalValue(value: _gasPrice) } else { gasPrice = nil @@ -70,11 +70,11 @@ class LegacyEvmFeeViewModel { spinnerVisible = true feeValue = nil gasLimit = "n/a".localized - case .failed(_): + case .failed: spinnerVisible = false feeValue = .error(text: "n/a".localized) gasLimit = "n/a".localized - case .completed(let fallibleTransaction): + case let .completed(fallibleTransaction): spinnerVisible = false let gasData = fallibleTransaction.data.gasData @@ -82,8 +82,8 @@ class LegacyEvmFeeViewModel { let tilda = gasData.isSurcharged if fallibleTransaction.errors.isEmpty, let coinValue = amountData.coinValue.formattedFull { feeValue = .regular( - text: "\(tilda ? "~" : "")\(coinValue)", - secondaryText: amountData.currencyValue?.formattedFull.map { "\(tilda ? "~" : "")\($0)" } + text: "\(tilda ? "~" : "")\(coinValue)", + secondaryText: amountData.currencyValue?.formattedFull.map { "\(tilda ? "~" : "")\($0)" } ) } else { feeValue = .error(text: "n/a".localized) @@ -97,14 +97,12 @@ class LegacyEvmFeeViewModel { gasLimitRelay.accept(gasLimit) } - private func sync(usingRecommended: Bool) { - alteredStateRelay.accept(Void()) + private func sync(usingRecommended _: Bool) { + alteredStateRelay.accept(()) } - } extension LegacyEvmFeeViewModel { - var altered: Bool { !gasPriceService.usingRecommended } @@ -132,11 +130,9 @@ extension LegacyEvmFeeViewModel { var cautionTypeDriver: Driver { cautionTypeRelay.asDriver() } - } extension LegacyEvmFeeViewModel: IFeeViewModel { - var valueDriver: Driver { valueRelay.asDriver() } @@ -144,5 +140,4 @@ extension LegacyEvmFeeViewModel: IFeeViewModel { var spinnerVisibleDriver: Driver { spinnerVisibleRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyGasPriceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyGasPriceService.swift index 6ad5bada66..fa87f594ef 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyGasPriceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Fee/Legacy/LegacyGasPriceService.swift @@ -53,11 +53,11 @@ class LegacyGasPriceService { } status = .completed(FallibleData( - data: EvmFeeModule.GasPrices( - recommended: .legacy(gasPrice: recommendedGasPrice), - userDefined: .legacy(gasPrice: legacyGasPrice) - ), - errors: [], warnings: warnings + data: EvmFeeModule.GasPrices( + recommended: .legacy(gasPrice: recommendedGasPrice), + userDefined: .legacy(gasPrice: legacyGasPrice) + ), + errors: [], warnings: warnings )) } } @@ -69,7 +69,6 @@ extension LegacyGasPriceService: IGasPriceService { } extension LegacyGasPriceService { - var usingRecommendedObservable: Observable { usingRecommendedRelay.asObservable() } @@ -100,5 +99,4 @@ extension LegacyGasPriceService { ) .disposed(by: disposeBag) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceDataSource.swift index 6fde5493cf..e5151815b3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceDataSource.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class NonceDataSource { private let viewModel: NonceViewModel @@ -13,8 +13,8 @@ class NonceDataSource { private let nonceCell = StepperAmountInputCell(allowFractionalNumbers: false) weak var tableView: SectionsTableView? - var onOpenInfo: ((String, String) -> ())? = nil - var onUpdateAlteredState: (() -> ())? = nil + var onOpenInfo: ((String, String) -> Void)? + var onUpdateAlteredState: (() -> Void)? init(viewModel: NonceViewModel) { self.viewModel = viewModel @@ -27,40 +27,37 @@ class NonceDataSource { subscribe(disposeBag, viewModel.valueDriver) { [weak self] in self?.nonceCell.value = $0 } subscribe(disposeBag, viewModel.cautionTypeDriver) { [weak self] in self?.nonceCell.set(cautionType: $0) } } - } extension NonceDataSource: IEvmSendSettingsDataSource { - var altered: Bool { viewModel.altered } var buildSections: [SectionProtocol] { - guard let tableView = tableView, !viewModel.frozen else { + guard let tableView, !viewModel.frozen else { return [] } return [ Section( - id: "nonce", - headerState: .margin(height: .margin24), - rows: [ - tableView.subtitleWithInfoButtonRow(text: "evm_send_settings.nonce".localized, uppercase: false) { [weak self] in - self?.onOpenInfo?("evm_send_settings.nonce".localized, "evm_send_settings.nonce.info".localized) - }, - StaticRow( - cell: nonceCell, - id: "nonce-input", - height: nonceCell.cellHeight - ) - ] - ) + id: "nonce", + headerState: .margin(height: .margin24), + rows: [ + tableView.subtitleWithInfoButtonRow(text: "evm_send_settings.nonce".localized, uppercase: false) { [weak self] in + self?.onOpenInfo?("evm_send_settings.nonce".localized, "evm_send_settings.nonce.info".localized) + }, + StaticRow( + cell: nonceCell, + id: "nonce-input", + height: nonceCell.cellHeight + ), + ] + ), ] } func onTapReset() { viewModel.reset() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceService.swift index b3a358dbe5..283a58e0eb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceService.swift @@ -1,6 +1,6 @@ import EvmKit -import RxSwift import RxCocoa +import RxSwift class NonceService { private var disposeBag = DisposeBag() @@ -13,6 +13,7 @@ class NonceService { sync() } } + let frozen: Bool var usingRecommended = true { didSet { usingRecommendedRelay.accept(usingRecommended) } } @@ -49,11 +50,9 @@ class NonceService { status = .completed(FallibleData(data: nonce, errors: errors, warnings: [])) } - } extension NonceService { - var statusObservable: Observable>> { statusRelay.asObservable() } @@ -77,26 +76,23 @@ extension NonceService { status = .loading Single.zip(evmKit.nonceSingle(defaultBlockParameter: .pending), evmKit.nonceSingle(defaultBlockParameter: .latest)) - .subscribe( - onSuccess: { [weak self] noncePending, nonceLatest in - self?.minimumNonce = nonceLatest - self?.recommendedNonce = noncePending - self?.usingRecommended = true - self?.nonce = noncePending - }, - onError: { [weak self] error in - self?.status = .failed(error) - } - ) - .disposed(by: disposeBag) + .subscribe( + onSuccess: { [weak self] noncePending, nonceLatest in + self?.minimumNonce = nonceLatest + self?.recommendedNonce = noncePending + self?.usingRecommended = true + self?.nonce = noncePending + }, + onError: { [weak self] error in + self?.status = .failed(error) + } + ) + .disposed(by: disposeBag) } - } extension NonceService { - enum NonceError: Error { case alreadyInUse } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceViewModel.swift index 6f1c19b369..a280ab3f78 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/EvmSendSettings/Nonce/NonceViewModel.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxCocoa +import RxSwift class NonceViewModel { private let disposeBag = DisposeBag() @@ -29,10 +29,10 @@ class NonceViewModel { case .loading: cautionType = nil nonce = nil - case .failed(_): + case .failed: cautionType = .error nonce = nil - case .completed(let nonceData): + case let .completed(nonceData): nonce = Decimal(nonceData.data) cautionType = nonceData.cautionType } @@ -41,14 +41,12 @@ class NonceViewModel { valueRelay.accept(nonce) } - private func sync(usingRecommended: Bool) { - alteredStateRelay.accept(Void()) + private func sync(usingRecommended _: Bool) { + alteredStateRelay.accept(()) } - } extension NonceViewModel { - var altered: Bool { !service.usingRecommended } @@ -72,5 +70,4 @@ extension NonceViewModel { var cautionTypeDriver: Driver { cautionTypeRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyModule.swift index 24d2cc6c56..21b8e64648 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyModule.swift @@ -1,22 +1,18 @@ -import UIKit import ThemeKit +import UIKit struct ExtendedKeyModule { - static func viewController(mode: Mode, accountType: AccountType) -> UIViewController { let service = ExtendedKeyService(mode: mode, accountType: accountType) let viewModel = ExtendedKeyViewModel(service: service) return ExtendedKeyViewController(viewModel: viewModel) } - } extension ExtendedKeyModule { - enum Mode { case bip32RootKey case accountExtendedPrivateKey case accountExtendedPublicKey } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyService.swift index a4ab9fdee8..89e6a37aec 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyService.swift @@ -1,11 +1,11 @@ +import BitcoinCashKit +import BitcoinKit +import DashKit import Foundation -import RxSwift -import RxRelay import HdWalletKit -import BitcoinKit -import BitcoinCashKit import LitecoinKit -import DashKit +import RxRelay +import RxSwift class ExtendedKeyService { let mode: ExtendedKeyModule.Mode @@ -32,8 +32,8 @@ class ExtendedKeyService { private func syncDerivation() { switch accountType { - case .hdExtendedKey(let key): - let derivations = key.purposes.map { $0.mnemonicDerivation } + case let .hdExtendedKey(key): + let derivations = key.purposes.map(\.mnemonicDerivation) if !derivations.contains(derivation) { derivation = derivations[0] } @@ -68,7 +68,7 @@ class ExtendedKeyService { switch accountType { case .mnemonic: return blockchain - case .hdExtendedKey(let extendedKey): + case let .hdExtendedKey(extendedKey): switch extendedKey.derivedType { case .master: return blockchain default: return nil @@ -86,7 +86,7 @@ class ExtendedKeyService { switch accountType { case .mnemonic: return account - case .hdExtendedKey(let extendedKey): + case let .hdExtendedKey(extendedKey): switch extendedKey.derivedType { case .master: return account default: return nil @@ -105,9 +105,9 @@ class ExtendedKeyService { } return key(rootKey: rootKey) - case .hdExtendedKey(let extendedKey): + case let .hdExtendedKey(extendedKey): switch extendedKey { - case .private(let privateKey): + case let .private(privateKey): switch extendedKey.derivedType { case .master: return key(rootKey: privateKey) @@ -119,7 +119,7 @@ class ExtendedKeyService { } default: return nil } - case .public(let publicKey): + case let .public(publicKey): switch extendedKey.derivedType { case .account: switch mode { @@ -143,13 +143,13 @@ class ExtendedKeyService { private func syncItem() { item = Item( - derivation: derivation, - derivationSwitchable: derivationSwitchable, - blockchain: resolvedBlockchain, - blockchainSwitchable: blockchainSwitchable, - account: resolvedAccount, - key: resolvedKey, - keyIsPrivate: keyIsPrivate + derivation: derivation, + derivationSwitchable: derivationSwitchable, + blockchain: resolvedBlockchain, + blockchainSwitchable: blockchainSwitchable, + account: resolvedAccount, + key: resolvedKey, + keyIsPrivate: keyIsPrivate ) } @@ -169,7 +169,7 @@ class ExtendedKeyService { } private func rootKey(seed: Data?) -> HDPrivateKey? { - guard let seed = seed else { + guard let seed else { return nil } @@ -179,18 +179,16 @@ class ExtendedKeyService { return HDPrivateKey(seed: seed, xPrivKey: version.rawValue) } - } extension ExtendedKeyService { - var itemObservable: Observable { itemRelay.asObservable() } var supportedBlockchains: [Blockchain] { var coinTypesDerivableFromKey = [HDExtendedKeyVersion.ExtendedKeyCoinType]() - if case .hdExtendedKey(let key) = accountType { + if case let .hdExtendedKey(key) = accountType { coinTypesDerivableFromKey.append(contentsOf: key.coinTypes) } @@ -226,11 +224,9 @@ extension ExtendedKeyService { self.account = account syncItem() } - } extension ExtendedKeyService { - struct Item { let derivation: MnemonicDerivation let derivationSwitchable: Bool @@ -276,5 +272,4 @@ extension ExtendedKeyService { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewController.swift index c0d570b70c..65a6fe06ab 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import RxSwift +import ComponentKit import RxCocoa +import RxSwift +import SectionsTableView import SnapKit import ThemeKit -import SectionsTableView -import ComponentKit +import UIKit class ExtendedKeyViewController: ThemeViewController { private let viewModel: ExtendedKeyViewModel @@ -22,7 +22,8 @@ class ExtendedKeyViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -99,8 +100,8 @@ class ExtendedKeyViewController: ThemeViewController { private func onTapDerivation() { let alertController = AlertRouter.module( - title: "extended_key.purpose".localized, - viewItems: viewModel.derivationViewItems + title: "extended_key.purpose".localized, + viewItems: viewModel.derivationViewItems ) { [weak self] index in self?.viewModel.onSelectDerivation(index: index) } @@ -110,8 +111,8 @@ class ExtendedKeyViewController: ThemeViewController { private func onTapBlockchain() { let alertController = AlertRouter.module( - title: "extended_key.blockchain".localized, - viewItems: viewModel.blockchainViewItems + title: "extended_key.blockchain".localized, + viewItems: viewModel.blockchainViewItems ) { [weak self] index in self?.viewModel.onSelectBlockchain(index: index) } @@ -121,67 +122,65 @@ class ExtendedKeyViewController: ThemeViewController { private func onTapAccount() { let alertController = AlertRouter.module( - title: "extended_key.account".localized, - viewItems: viewModel.accountViewItems + title: "extended_key.account".localized, + viewItems: viewModel.accountViewItems ) { [weak self] index in self?.viewModel.onSelectAccount(index: index) } present(alertController, animated: true) } - } extension ExtendedKeyViewController: SectionsDataSource { - private func controlRow(item: ControlItem, isFirst: Bool = false, isLast: Bool = false) -> RowProtocol { tableView.universalRow48( - id: item.id, - title: .body(item.title), - value: .subhead1(item.value, color: .themeGray), - accessoryType: item.action == nil ? .none : .dropdown, - autoDeselect: true, - isFirst: isFirst, - isLast: isLast, - action: item.action + id: item.id, + title: .body(item.title), + value: .subhead1(item.value, color: .themeGray), + accessoryType: item.action == nil ? .none : .dropdown, + autoDeselect: true, + isFirst: isFirst, + isLast: isLast, + action: item.action ) } func buildSections() -> [SectionProtocol] { var controlItems: [ControlItem] = [ ControlItem( - id: "derivation", - title: "extended_key.purpose".localized, - value: viewItem.derivation, - action: viewItem.derivationSwitchable ? { [weak self] in - self?.onTapDerivation() - } : nil - ) + id: "derivation", + title: "extended_key.purpose".localized, + value: viewItem.derivation, + action: viewItem.derivationSwitchable ? { [weak self] in + self?.onTapDerivation() + } : nil + ), ] if let blockchain = viewItem.blockchain { controlItems.append( - ControlItem( - id: "blockchain", - title: "extended_key.blockchain".localized, - value: blockchain, - action: viewItem.blockchainSwitchable ? { [weak self] in - self?.onTapBlockchain() - } : nil - ) + ControlItem( + id: "blockchain", + title: "extended_key.blockchain".localized, + value: blockchain, + action: viewItem.blockchainSwitchable ? { [weak self] in + self?.onTapBlockchain() + } : nil + ) ) } if let account = viewItem.account { controlItems.append( - ControlItem( - id: "account", - title: "extended_key.account".localized, - value: account, - action: { [weak self] in - self?.onTapAccount() - } - ) + ControlItem( + id: "account", + title: "extended_key.account".localized, + value: account, + action: { [weak self] in + self?.onTapAccount() + } + ) ) } @@ -195,76 +194,73 @@ extension ExtendedKeyViewController: SectionsDataSource { if viewItem.keyIsPrivate { sections.append( - Section( + Section( + id: "warning", + rows: [ + tableView.highlightedDescriptionRow( id: "warning", - rows: [ - tableView.highlightedDescriptionRow( - id: "warning", - text: "recovery_phrase.warning".localized(AppConfig.appName) - ) - ] - ) + text: "recovery_phrase.warning".localized(AppConfig.appName) + ), + ] + ) ) } sections.append(contentsOf: [ Section( - id: "controls", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: controlItems.enumerated().map { index, item in - controlRow(item: item, isFirst: index == 0, isLast: index == controlItems.count - 1) - } + id: "controls", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: controlItems.enumerated().map { index, item in + controlRow(item: item, isFirst: index == 0, isLast: index == controlItems.count - 1) + } ), Section( - id: "key", - footerState: .margin(height: .margin32), - rows: [ - CellBuilderNew.row( - rootElement: .text { component in - component.font = keyHidden ? .subhead2 : textFont - component.textColor = keyHidden ? .themeGray : .themeLeah - component.text = keyHidden ? "extended_key.tap_to_show".localized : key - component.textAlignment = keyHidden ? .center : .left - component.numberOfLines = 0 - }, - layoutMargins: UIEdgeInsets(top: 0, left: .margin24, bottom: 0, right: .margin24), - tableView: tableView, - id: "key", - dynamicHeight: { width in - CellBuilderNew.height( - containerWidth: width, - backgroundStyle: backgroundStyle, - text: key, - font: textFont, - verticalPadding: .margin24, - elements: [.multiline] - ) - }, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, cornerRadius: .cornerRadius24, isFirst: true, isLast: true) - cell.selectionStyle = .none - }, - action: viewItem.keyIsPrivate ? { [weak self] in - self?.toggleKeyHidden() - } : nil - ) - ] - ) + id: "key", + footerState: .margin(height: .margin32), + rows: [ + CellBuilderNew.row( + rootElement: .text { component in + component.font = keyHidden ? .subhead2 : textFont + component.textColor = keyHidden ? .themeGray : .themeLeah + component.text = keyHidden ? "extended_key.tap_to_show".localized : key + component.textAlignment = keyHidden ? .center : .left + component.numberOfLines = 0 + }, + layoutMargins: UIEdgeInsets(top: 0, left: .margin24, bottom: 0, right: .margin24), + tableView: tableView, + id: "key", + dynamicHeight: { width in + CellBuilderNew.height( + containerWidth: width, + backgroundStyle: backgroundStyle, + text: key, + font: textFont, + verticalPadding: .margin24, + elements: [.multiline] + ) + }, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, cornerRadius: .cornerRadius24, isFirst: true, isLast: true) + cell.selectionStyle = .none + }, + action: viewItem.keyIsPrivate ? { [weak self] in + self?.toggleKeyHidden() + } : nil + ), + ] + ), ]) return sections } - } extension ExtendedKeyViewController { - struct ControlItem { let id: String let title: String let value: String - var action: (() -> ())? + var action: (() -> Void)? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewModel.swift index d86295397a..b9e697bc4c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ExtendedKey/ExtendedKeyViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class ExtendedKeyViewModel { private let service: ExtendedKeyService @@ -18,13 +18,13 @@ class ExtendedKeyViewModel { private func sync(item: ExtendedKeyService.Item) { let viewItem = ViewItem( - derivation: item.derivation.rawValue.uppercased(), - derivationSwitchable: item.derivationSwitchable, - blockchain: item.blockchain.map { $0.title }, - blockchainSwitchable: item.blockchainSwitchable, - account: item.account.map { "\($0)" }, - key: item.key ?? "", - keyIsPrivate: item.keyIsPrivate + derivation: item.derivation.rawValue.uppercased(), + derivationSwitchable: item.derivationSwitchable, + blockchain: item.blockchain.map(\.title), + blockchainSwitchable: item.blockchainSwitchable, + account: item.account.map { "\($0)" }, + key: item.key ?? "", + keyIsPrivate: item.keyIsPrivate ) viewItemRelay.accept(viewItem) @@ -32,7 +32,6 @@ class ExtendedKeyViewModel { } extension ExtendedKeyViewModel { - var viewItemDriver: Driver { viewItemRelay.asDriver() } @@ -48,8 +47,8 @@ extension ExtendedKeyViewModel { var derivationViewItems: [AlertViewItem] { MnemonicDerivation.allCases.map { derivation in AlertViewItem( - text: derivation.rawValue.uppercased(), - selected: service.item.derivation == derivation + text: derivation.rawValue.uppercased(), + selected: service.item.derivation == derivation ) } } @@ -57,17 +56,17 @@ extension ExtendedKeyViewModel { var blockchainViewItems: [AlertViewItem] { service.supportedBlockchains.map { blockchain in AlertViewItem( - text: blockchain.title, - selected: service.item.blockchain == blockchain + text: blockchain.title, + selected: service.item.blockchain == blockchain ) } } var accountViewItems: [AlertViewItem] { - Range(0...5).map { account in + Range(0 ... 5).map { account in AlertViewItem( - text: "\(account)", - selected: service.item.account == account + text: "\(account)", + selected: service.item.account == account ) } } @@ -83,11 +82,9 @@ extension ExtendedKeyViewModel { func onSelectAccount(index: Int) { service.set(account: index) } - } extension ExtendedKeyViewModel { - struct ViewItem { let derivation: String let derivationSwitchable: Bool @@ -101,5 +98,4 @@ extension ExtendedKeyViewModel { ViewItem(derivation: "", derivationSwitchable: false, blockchain: nil, blockchainSwitchable: false, account: nil, key: "", keyIsPrivate: false) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqCell.swift index 6420ffcd8c..fbedf713e5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import ComponentKit +import ThemeKit +import UIKit class FaqCell: BaseSelectableThemeCell { private static let padding: CGFloat = .margin16 @@ -29,16 +29,13 @@ class FaqCell: BaseSelectableThemeCell { get { label.text } set { label.text = newValue } } - } extension FaqCell { - static func height(containerWidth: CGFloat, text: String, backgroundStyle: BackgroundStyle) -> CGFloat { let textWidth = containerWidth - 2 * padding - Self.margin(backgroundStyle: backgroundStyle).width let textHeight = text.height(forContainerWidth: textWidth, font: font) return padding + textHeight + padding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqModule.swift index ed09a12624..07ba75f0b3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqModule.swift @@ -2,21 +2,19 @@ import Foundation import UIKit struct FaqModule { - static func viewController() -> UIViewController { let repository = FaqRepository( - networkManager: App.shared.networkManager, - reachabilityManager: App.shared.reachabilityManager + networkManager: App.shared.networkManager, + reachabilityManager: App.shared.reachabilityManager ) let service = FaqService( - repository: repository, - languageManager: LanguageManager.shared + repository: repository, + languageManager: LanguageManager.shared ) let viewModel = FaqViewModel(service: service) return FaqViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqRepository.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqRepository.swift index f8f038e5b3..d6edc28abf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqRepository.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqRepository.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import HsToolKit +import RxRelay +import RxSwift class FaqRepository { private let disposeBag = DisposeBag() @@ -15,13 +15,13 @@ class FaqRepository { self.reachabilityManager = reachabilityManager reachabilityManager.reachabilityObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] reachable in - if reachable { - self?.onReachable() - } - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] reachable in + if reachable { + self?.onReachable() + } + }) + .disposed(by: disposeBag) fetch() } @@ -38,27 +38,23 @@ class FaqRepository { let request = networkManager.session.request(AppConfig.faqIndexUrl) networkManager.single(request: request, mapper: self) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] faq in - self?.faqRelay.accept(.completed(faq)) - }, onError: { [weak self] error in - self?.faqRelay.accept(.failed(error)) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] faq in + self?.faqRelay.accept(.completed(faq)) + }, onError: { [weak self] error in + self?.faqRelay.accept(.failed(error)) + }) + .disposed(by: disposeBag) } - } extension FaqRepository { - var faqObservable: Observable> { faqRelay.asObservable() } - } extension FaqRepository: IApiMapper { - public func map(statusCode: Int, data: Any?) throws -> [FaqSection] { guard let array = data as? [[String: Any]] else { throw NetworkManager.RequestError.invalidResponse(statusCode: statusCode, data: data) @@ -86,5 +82,4 @@ extension FaqRepository: IApiMapper { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqService.swift index 32973d792f..2f7ca35c6a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqService.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import HsToolKit +import RxSwift class FaqService { private let repository: FaqRepository @@ -25,19 +25,17 @@ class FaqService { } return Item( - text: faq.text, - url: URL(string: faq.fileUrl, relativeTo: faqIndexUrl) + text: faq.text, + url: URL(string: faq.fileUrl, relativeTo: faqIndexUrl) ) } return SectionItem(title: title, items: items) } } - } extension FaqService { - var faqObservable: Observable> { repository.faqObservable.map { [weak self] dataState in dataState.map { [weak self] in @@ -45,11 +43,9 @@ extension FaqService { } } } - } extension FaqService { - struct SectionItem { let title: String let items: [Item] @@ -59,5 +55,4 @@ extension FaqService { let text: String let url: URL? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewController.swift index e5c70e3010..b820b8858c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import SnapKit -import ThemeKit -import SectionsTableView +import ComponentKit import HUD import RxSwift -import ComponentKit +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class FaqViewController: ThemeViewController { private let viewModel: FaqViewModel @@ -29,7 +29,8 @@ class FaqViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -68,21 +69,21 @@ class FaqViewController: ThemeViewController { errorView.image = UIImage(named: "not_available_48") viewModel.sectionItemsDriver - .drive(onNext: { [weak self] in self?.sync(sectionItems: $0) }) - .disposed(by: disposeBag) + .drive(onNext: { [weak self] in self?.sync(sectionItems: $0) }) + .disposed(by: disposeBag) viewModel.loadingDriver - .drive(onNext: { [weak self] loading in - self?.setSpinner(visible: loading) - }) - .disposed(by: disposeBag) + .drive(onNext: { [weak self] loading in + self?.setSpinner(visible: loading) + }) + .disposed(by: disposeBag) viewModel.errorDriver - .drive(onNext: { [weak self] error in - self?.errorView.isHidden = error == nil - self?.errorView.text = error?.smartDescription - }) - .disposed(by: disposeBag) + .drive(onNext: { [weak self] error in + self?.errorView.isHidden = error == nil + self?.errorView.text = error?.smartDescription + }) + .disposed(by: disposeBag) tableView.buildSections() } @@ -116,43 +117,41 @@ class FaqViewController: ThemeViewController { currentSection = index tableView.reload() } - } extension FaqViewController: SectionsDataSource { - private var transparentRow: RowProtocol { Row(id: "transparent_row", height: 20) } private func itemsSection(sectionIndex: Int, items: [FaqService.Item]) -> SectionProtocol { Section( - id: "items-\(sectionIndex)", - headerState: .static(view: sectionFilterView, height: .heightSingleLineCell), - footerState: .marginColor(height: .margin32, color: .clear), - rows: [transparentRow] + items.enumerated().map { index, item in - let isFirst = index == 0 - let isLast = index == items.count - 1 - - return Row( - id: "faq-\(sectionIndex)-\(index)", - dynamicHeight: { containerWidth in - FaqCell.height(containerWidth: containerWidth, text: item.text, backgroundStyle: .lawrence) - }, - bind: { cell, _ in - cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) - cell.title = item.text - }, - action: { [weak self] _ in - guard let url = item.url else { - return - } - - let module = MarkdownModule.viewController(url: url, handleRelativeUrl: false) - self?.navigationController?.pushViewController(module, animated: true) - } - ) - } + id: "items-\(sectionIndex)", + headerState: .static(view: sectionFilterView, height: .heightSingleLineCell), + footerState: .marginColor(height: .margin32, color: .clear), + rows: [transparentRow] + items.enumerated().map { index, item in + let isFirst = index == 0 + let isLast = index == items.count - 1 + + return Row( + id: "faq-\(sectionIndex)-\(index)", + dynamicHeight: { containerWidth in + FaqCell.height(containerWidth: containerWidth, text: item.text, backgroundStyle: .lawrence) + }, + bind: { cell, _ in + cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) + cell.title = item.text + }, + action: { [weak self] _ in + guard let url = item.url else { + return + } + + let module = MarkdownModule.viewController(url: url, handleRelativeUrl: false) + self?.navigationController?.pushViewController(module, animated: true) + } + ) + } ) } @@ -167,5 +166,4 @@ extension FaqViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewModel.swift index 8efc7c63ff..3655162a01 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Faq/FaqViewModel.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxCocoa +import RxSwift class FaqViewModel { private let disposeBag = DisposeBag() @@ -15,10 +15,10 @@ class FaqViewModel { self.service = service service.faqObservable - .subscribe(onNext: { [weak self] dataStatus in - self?.handle(dataStatus: dataStatus) - }) - .disposed(by: disposeBag) + .subscribe(onNext: { [weak self] dataStatus in + self?.handle(dataStatus: dataStatus) + }) + .disposed(by: disposeBag) } private func handle(dataStatus: DataStatus<[FaqService.SectionItem]>) { @@ -28,23 +28,21 @@ class FaqViewModel { loadingRelay.accept(false) } - if case .completed(let items) = dataStatus { + if case let .completed(items) = dataStatus { sectionItemsRelay.accept(items) } else { sectionItemsRelay.accept([]) } - if case .failed(let error) = dataStatus { + if case let .failed(error) = dataStatus { errorRelay.accept(error.convertedError) } else { errorRelay.accept(nil) } } - } extension FaqViewModel { - var sectionItemsDriver: Driver<[FaqService.SectionItem]> { sectionItemsRelay.asDriver() } @@ -56,5 +54,4 @@ extension FaqViewModel { var errorDriver: Driver { errorRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Favorites/FavoritesManager.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Favorites/FavoritesManager.swift index 26bffa0dea..5eda17f1c3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Favorites/FavoritesManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Favorites/FavoritesManager.swift @@ -27,7 +27,7 @@ extension FavoritesManager { } var allCoinUids: [String] { - storage.favoriteCoinRecords.map { $0.coinUid } + storage.favoriteCoinRecords.map(\.coinUid) } func add(coinUid: String) { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/Cells/GuideCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/Cells/GuideCell.swift index 40267e3bc6..372848c11a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/Cells/GuideCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/Cells/GuideCell.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import Kingfisher import ComponentKit +import Kingfisher +import SnapKit +import ThemeKit +import UIKit class GuideCell: UITableViewCell { private static let cardTopMargin: CGFloat = 0 @@ -65,7 +65,8 @@ class GuideCell: UITableViewCell { titleLabel.textColor = .themeLeah } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -81,19 +82,15 @@ class GuideCell: UITableViewCell { dateLabel.text = GuideCell.formattedDate(viewItem: viewItem) titleLabel.text = viewItem.title } - } extension GuideCell { - private static func formattedDate(viewItem: GuideViewItem) -> String { DateFormatter.cachedFormatter(format: "MMMM d, yyyy").string(from: viewItem.date) } - } extension GuideCell { - static func height(containerWidth: CGFloat, viewItem: GuideViewItem, first: Bool, last: Bool) -> CGFloat { let titleWidth = containerWidth - 2 * cardHorizontalMargin - 2 * titleHorizontalMargin let titleHeight = viewItem.title.height(forContainerWidth: titleWidth, font: titleFont) @@ -103,5 +100,4 @@ extension GuideCell { return cardTop + imageHeight + dateTopMargin + dateFont.lineHeight + titleTopMargin + titleHeight + titleBottomMargin + cardBottom } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesModule.swift index 50252cd5b9..5e8773121c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesModule.swift @@ -1,7 +1,7 @@ import Foundation -import UIKit -import RxSwift import RxCocoa +import RxSwift +import UIKit protocol IGuidesViewModel { var filters: Driver<[String]> { get } @@ -37,12 +37,11 @@ struct GuideViewItem { let url: URL? } -struct GuidesModule { - +enum GuidesModule { static func instance() -> UIViewController { let repository = GuidesRepository( - guidesManager: App.shared.guidesManager, - reachabilityManager: App.shared.reachabilityManager + guidesManager: App.shared.guidesManager, + reachabilityManager: App.shared.reachabilityManager ) let service = GuidesService(repository: repository, languageManager: LanguageManager.shared) @@ -50,5 +49,4 @@ struct GuidesModule { return GuidesViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesRepository.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesRepository.swift index 63b9ee1403..b441741fa3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesRepository.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesRepository.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import HsToolKit +import RxRelay +import RxSwift class GuidesRepository { private let disposeBag = DisposeBag() @@ -15,13 +15,13 @@ class GuidesRepository { self.reachabilityManager = reachabilityManager reachabilityManager.reachabilityObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] reachable in - if reachable { - self?.onReachable() - } - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] reachable in + if reachable { + self?.onReachable() + } + }) + .disposed(by: disposeBag) fetch() } @@ -36,17 +36,16 @@ class GuidesRepository { categoriesRelay.accept(.loading) guidesManager.guideCategoriesSingle(url: AppConfig.guidesIndexUrl) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] categories in - self?.categoriesRelay.accept(.success(result: categories)) - }, onError: { [weak self] error in - self?.categoriesRelay.accept(.error(error: error)) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] categories in + self?.categoriesRelay.accept(.success(result: categories)) + }, onError: { [weak self] error in + self?.categoriesRelay.accept(.error(error: error)) + }) + .disposed(by: disposeBag) } var categories: Observable> { categoriesRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesService.swift index 86855abd3e..052bb9fb8f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import HsToolKit +import RxRelay +import RxSwift class GuidesService { private let disposeBag = DisposeBag() @@ -22,8 +22,8 @@ class GuidesService { let guides = category.guides(language: languageManager.currentLanguage, fallbackLanguage: LanguageManager.fallbackLanguage) return GuideCategoryItem( - title: title, - items: guides.map { guideItem(guide: $0) } + title: title, + items: guides.map { guideItem(guide: $0) } ) } @@ -31,10 +31,10 @@ class GuidesService { let guidesIndexUrl = AppConfig.guidesIndexUrl return GuideItem( - title: guide.title, - imageUrl: guide.imageUrl.flatMap { URL(string: $0, relativeTo: guidesIndexUrl) }, - date: guide.date, - url: URL(string: guide.fileUrl, relativeTo: guidesIndexUrl) + title: guide.title, + imageUrl: guide.imageUrl.flatMap { URL(string: $0, relativeTo: guidesIndexUrl) }, + date: guide.date, + url: URL(string: guide.fileUrl, relativeTo: guidesIndexUrl) ) } @@ -43,15 +43,14 @@ class GuidesService { switch dataState { case .loading: return .loading - case .success(let categories): + case let .success(categories): let categoryItems = categories.compactMap { self?.categoryItem(category: $0) } return .success(result: categoryItems) - case .error(let error): + case let .error(error): return .error(error: error) } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewController.swift index 707f15d5e3..517bd17325 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import SnapKit -import ThemeKit -import SectionsTableView import HUD import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class GuidesViewController: ThemeViewController { private let viewModel: IGuidesViewModel @@ -27,7 +27,8 @@ class GuidesViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -66,32 +67,32 @@ class GuidesViewController: ThemeViewController { errorView.image = UIImage(named: "not_available_48") viewModel.filters - .drive(onNext: { [weak self] filters in - self?.filterHeaderView.reload(filters: filters.map { filter in - FilterView.ViewItem.item(title: filter) - }) + .drive(onNext: { [weak self] filters in + self?.filterHeaderView.reload(filters: filters.map { filter in + FilterView.ViewItem.item(title: filter) }) - .disposed(by: disposeBag) + }) + .disposed(by: disposeBag) viewModel.viewItems - .drive(onNext: { [weak self] viewItems in - self?.viewItems = viewItems - self?.tableView.reloadData() - }) - .disposed(by: disposeBag) + .drive(onNext: { [weak self] viewItems in + self?.viewItems = viewItems + self?.tableView.reloadData() + }) + .disposed(by: disposeBag) viewModel.isLoading - .drive(onNext: { [weak self] visible in - self?.setSpinner(visible: visible) - }) - .disposed(by: disposeBag) + .drive(onNext: { [weak self] visible in + self?.setSpinner(visible: visible) + }) + .disposed(by: disposeBag) viewModel.error - .drive(onNext: { [weak self] error in - self?.errorView.isHidden = error == nil - self?.errorView.text = error?.smartDescription - }) - .disposed(by: disposeBag) + .drive(onNext: { [weak self] error in + self?.errorView.isHidden = error == nil + self?.errorView.text = error?.smartDescription + }) + .disposed(by: disposeBag) } private func setSpinner(visible: Bool) { @@ -103,12 +104,10 @@ class GuidesViewController: ThemeViewController { spinner.stopAnimating() } } - } extension GuidesViewController: UITableViewDataSource, UITableViewDelegate { - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { viewItems.count } @@ -116,19 +115,19 @@ extension GuidesViewController: UITableViewDataSource, UITableViewDelegate { tableView.dequeueReusableCell(withIdentifier: String(describing: GuideCell.self), for: indexPath) } - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { if let cell = cell as? GuideCell { let index = indexPath.row cell.bind( - viewItem: viewItems[index], - first: index == 0, - last: index == viewItems.count - 1 + viewItem: viewItems[index], + first: index == 0, + last: index == viewItems.count - 1 ) } } - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) { let viewItem = viewItems[indexPath.row] guard let url = viewItem.url else { @@ -143,19 +142,18 @@ extension GuidesViewController: UITableViewDataSource, UITableViewDelegate { let index = indexPath.row return GuideCell.height( - containerWidth: tableView.width, - viewItem: viewItems[index], - first: index == 0, - last: index == viewItems.count - 1 + containerWidth: tableView.width, + viewItem: viewItems[index], + first: index == 0, + last: index == viewItems.count - 1 ) } - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { filterHeaderView.headerHeight } - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + func tableView(_: UITableView, viewForHeaderInSection _: Int) -> UIView? { filterHeaderView } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewModel.swift index fe53b637cb..d11cb65f7d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Guides/GuidesViewModel.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxCocoa +import RxSwift class GuidesViewModel { private let disposeBag = DisposeBag() @@ -19,10 +19,10 @@ class GuidesViewModel { self.service = service service.categories - .subscribe(onNext: { [weak self] dataState in - self?.handle(dataState: dataState) - }) - .disposed(by: disposeBag) + .subscribe(onNext: { [weak self] dataState in + self?.handle(dataState: dataState) + }) + .disposed(by: disposeBag) } private func handle(dataState: DataState<[GuideCategoryItem]>) { @@ -32,15 +32,15 @@ class GuidesViewModel { loadingRelay.accept(false) } - if case .success(let categories) = dataState { + if case let .success(categories) = dataState { self.categories = categories - filterViewItemsRelay.accept(categories.map { $0.title }) + filterViewItemsRelay.accept(categories.map(\.title)) syncViewItems() } - if case .error(let error) = dataState { + if case let .error(error) = dataState { errorRelay.accept(error.convertedError) } else { errorRelay.accept(nil) @@ -54,10 +54,10 @@ class GuidesViewModel { let viewItems = categories[currentCategoryIndex].items.map { item in GuideViewItem( - title: item.title, - date: item.date, - imageUrl: item.imageUrl, - url: item.url + title: item.title, + date: item.date, + imageUrl: item.imageUrl, + url: item.url ) } @@ -66,7 +66,6 @@ class GuidesViewModel { } extension GuidesViewModel: IGuidesViewModel { - var filters: Driver<[String]> { filterViewItemsRelay.asDriver() } @@ -88,5 +87,4 @@ extension GuidesViewModel: IGuidesViewModel { syncViewItems() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoModule.swift index 1503da0691..3d724cde72 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoModule.swift @@ -1,18 +1,15 @@ import SwiftUI -import UIKit import ThemeKit +import UIKit struct InfoModule { - static func viewController(viewItems: [ViewItem]) -> UIViewController { let viewController = InfoViewController(viewItems: viewItems) return ThemeNavigationController(rootViewController: viewController) } - } extension InfoModule { - enum ViewItem { case header1(text: String) case header3(text: String) @@ -22,70 +19,69 @@ extension InfoModule { static var feeInfo: UIViewController { viewController( - viewItems: [ - .header1(text: "send.fee_info.title".localized), - .text(text: "send.fee_info.description".localized(AppConfig.appName)) - ] + viewItems: [ + .header1(text: "send.fee_info.title".localized), + .text(text: "send.fee_info.description".localized(AppConfig.appName)), + ] ) } static var timeLockInfo: UIViewController { viewController( - viewItems: [ - .header1(text: "lock_info.title".localized), - .text(text: "lock_info.text".localized) - ] + viewItems: [ + .header1(text: "lock_info.title".localized), + .text(text: "lock_info.text".localized), + ] ) } static var restoreSourceInfo: some View { InfoView( - viewItems: [ - .header1(text: "blockchain_settings.info.restore_source".localized), - .text(text: "blockchain_settings.info.restore_source.content".localized(AppConfig.appName)), - ] + viewItems: [ + .header1(text: "blockchain_settings.info.restore_source".localized), + .text(text: "blockchain_settings.info.restore_source.content".localized(AppConfig.appName)), + ] ) - .ignoresSafeArea() + .ignoresSafeArea() } static var transactionInputsOutputsInfo: UIViewController { viewController( - viewItems: [ - .header1(text: "send.transaction_inputs_outputs_info.title".localized), - .text(text: "send.transaction_inputs_outputs_info.description".localized(AppConfig.appName, AppConfig.appName)), - .header3(text: "send.transaction_inputs_outputs_info.shuffle.title".localized), - .text(text: "send.transaction_inputs_outputs_info.shuffle.description".localized), - .header3(text: "send.transaction_inputs_outputs_info.deterministic.title".localized), - .text(text: "send.transaction_inputs_outputs_info.deterministic.description".localized), - ] + viewItems: [ + .header1(text: "send.transaction_inputs_outputs_info.title".localized), + .text(text: "send.transaction_inputs_outputs_info.description".localized(AppConfig.appName, AppConfig.appName)), + .header3(text: "send.transaction_inputs_outputs_info.shuffle.title".localized), + .text(text: "send.transaction_inputs_outputs_info.shuffle.description".localized), + .header3(text: "send.transaction_inputs_outputs_info.deterministic.title".localized), + .text(text: "send.transaction_inputs_outputs_info.deterministic.description".localized), + ] ) } static var rpcSourceInfo: UIViewController { viewController( - viewItems: [ - .header1(text: "blockchain_settings.info.rpc_source".localized), - .text(text: "blockchain_settings.info.rpc_source.content".localized(AppConfig.appName)), - ] + viewItems: [ + .header1(text: "blockchain_settings.info.rpc_source".localized), + .text(text: "blockchain_settings.info.rpc_source.content".localized(AppConfig.appName)), + ] ) } static var transactionStatusInfo: UIViewController { viewController( - viewItems: [ - .header1(text: "status_info.title".localized), - .header3(text: "status_info.pending.title".localized), - .text(text: "status_info.pending.content".localized(AppConfig.appName)), - .header3(text: "status_info.processing.title".localized), - .text(text: "status_info.processing.content".localized), - .header3(text: "status_info.completed.title".localized), - .text(text: "status_info.confirmed.content".localized), - .header3(text: "status_info.failed.title".localized), - .text(text: "status_info.failed.content".localized(AppConfig.appName)) - ] + viewItems: [ + .header1(text: "status_info.title".localized), + .header3(text: "status_info.pending.title".localized), + .text(text: "status_info.pending.content".localized(AppConfig.appName)), + .header3(text: "status_info.processing.title".localized), + .text(text: "status_info.processing.content".localized), + .header3(text: "status_info.completed.title".localized), + .text(text: "status_info.confirmed.content".localized), + .header3(text: "status_info.failed.title".localized), + .text(text: "status_info.failed.content".localized(AppConfig.appName)), + ] ) } - } struct InfoView: UIViewControllerRepresentable { @@ -93,11 +89,9 @@ struct InfoView: UIViewControllerRepresentable { let viewItems: [InfoModule.ViewItem] - func makeUIViewController(context: Context) -> UIViewController { + func makeUIViewController(context _: Context) -> UIViewController { InfoModule.viewController(viewItems: viewItems) } - func updateUIViewController(_ uiViewController: UIViewController, context: Context) { - } - + func updateUIViewController(_: UIViewController, context _: Context) {} } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoViewController.swift index cc5f61fa4a..d0b36e96c1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Info/InfoViewController.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SectionsTableView import ThemeKit -import ComponentKit +import UIKit class InfoViewController: ThemeViewController { private let viewItems: [InfoModule.ViewItem] @@ -14,7 +14,8 @@ class InfoViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -45,34 +46,31 @@ class InfoViewController: ThemeViewController { @objc private func onClose() { dismiss(animated: true) } - } extension InfoViewController: SectionsDataSource { - public func buildSections() -> [SectionProtocol] { [ Section( - id: "section", - footerState: .margin(height: .margin32), - rows: rows() - ) + id: "section", + footerState: .margin(height: .margin32), + rows: rows() + ), ] } private func rows() -> [RowProtocol] { viewItems.enumerated().map { index, viewItem in switch viewItem { - case .header1(let text): + case let .header1(text): return MarkdownViewController.header1Row(id: "header-\(index)", string: text) - case .header3(let text): + case let .header3(text): return MarkdownViewController.header3Row(id: "header-\(index)", string: text) - case .text(let text): + case let .text(text): return MarkdownViewController.textRow(id: "text-\(index)", string: text) - case .listItem(let text): + case let .listItem(text): return MarkdownViewController.listItemRow(id: "list-item-\(index)", string: text) } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchErrorViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchErrorViewController.swift index 8e661534bc..05d96b1b03 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchErrorViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchErrorViewController.swift @@ -1,8 +1,8 @@ -import UIKit +import ComponentKit import MessageUI import SnapKit import ThemeKit -import ComponentKit +import UIKit class LaunchErrorViewController: ThemeViewController { private let error: Error @@ -13,7 +13,8 @@ class LaunchErrorViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -65,9 +66,9 @@ class LaunchErrorViewController: ThemeViewController { @objc private func onTapReport() { let errorString = """ - Raw Error: \(error) - Localized Description: \(error.localizedDescription) - """ + Raw Error: \(error) + Localized Description: \(error.localizedDescription) + """ if MFMailComposeViewController.canSendMail() { let controller = MFMailComposeViewController() @@ -80,13 +81,10 @@ class LaunchErrorViewController: ThemeViewController { CopyHelper.copyAndNotify(value: errorString) } } - } extension LaunchErrorViewController: MFMailComposeViewControllerDelegate { - - func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error _: Error?) { controller.dismiss(animated: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchService.swift index 680ea368ac..20e64bde1e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Launch/LaunchService.swift @@ -22,7 +22,7 @@ extension LaunchService { return .cannotCheckPasscode } else if passcodeManager.isPasscodeSet { return .unlock - } else if accountManager.accounts.isEmpty && !localStorage.mainShownOnce { + } else if accountManager.accounts.isEmpty, !localStorage.mainShownOnce { return .intro } else { return .main diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/DeepLinkService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/DeepLinkService.swift index 73d513ad4f..71ea738682 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/DeepLinkService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/DeepLinkService.swift @@ -17,5 +17,4 @@ class DeepLinkService { func setDeepLinkShown() { deepLink = nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/JailbreakService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/JailbreakService.swift index 962a5c4323..8d054ce03d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/JailbreakService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/JailbreakService.swift @@ -16,5 +16,4 @@ class JailbreakService { func setAlertShown() { localStorage.jailbreakShownOnce = true } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainService.swift index 28ec1de5d2..7aac31ff90 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainService.swift @@ -101,7 +101,7 @@ extension MainService { } var initialTab: MainModule.Tab { - if let presetTab = presetTab { + if let presetTab { return presetTab } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift index ae76f0f3f8..37e5020981 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift @@ -70,7 +70,7 @@ class MainViewController: ThemeTabBarController { } private func handleDoubleClick(index: Int) { - if let viewControllers = viewControllers, viewControllers.count > index, let navigationController = viewControllers[index] as? UINavigationController, navigationController.topViewController is WalletViewController { + if let viewControllers, viewControllers.count > index, let navigationController = viewControllers[index] as? UINavigationController, navigationController.topViewController is WalletViewController { present(SwitchAccountModule.viewController(), animated: true) } } @@ -104,7 +104,7 @@ class MainViewController: ThemeTabBarController { } private func showReleaseNotes(url: URL?) { - guard let url = url else { + guard let url else { return } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesMarkdownConfig.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesMarkdownConfig.swift index c1d23dfc35..26f1210ac2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesMarkdownConfig.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesMarkdownConfig.swift @@ -1,14 +1,13 @@ +import Down import Foundation -import UIKit import ThemeKit -import Down +import UIKit struct ReleaseNotesMarkdownConfig { - private static let colors = StaticColorCollection( - heading1: .themeJacob, - heading2: .themeJacob, - body: .themeBran + heading1: .themeJacob, + heading2: .themeJacob, + body: .themeBran ) private static let paragraphStyles: StaticParagraphStyleCollection = { @@ -28,16 +27,15 @@ struct ReleaseNotesMarkdownConfig { static var config: DownStylerConfiguration { let fonts = StaticFontCollection( - heading1: .title3, - heading2: .headline2, - body: .body + heading1: .title3, + heading2: .headline2, + body: .body ) return DownStylerConfiguration( - fonts: fonts, - colors: colors, - paragraphStyles: paragraphStyles + fonts: fonts, + colors: colors, + paragraphStyles: paragraphStyles ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesService.swift index 02d35513d5..80064264b8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesService.swift @@ -1,9 +1,9 @@ import Foundation -import RxSwift import RxRelay +import RxSwift class ReleaseNotesService { - static private let releaseUrl = "https://api.github.com/repos/\(AppConfig.appGitHubAccount)/\(AppConfig.appGitHubRepository)/releases/tags/" + private static let releaseUrl = "https://api.github.com/repos/\(AppConfig.appGitHubAccount)/\(AppConfig.appGitHubRepository)/releases/tags/" private let appVersionManager: AppVersionManager @@ -23,5 +23,4 @@ class ReleaseNotesService { var lastVersionUrl: URL? { URL(string: Self.releaseUrl + appVersionManager.currentVersion.releaseNotesVersion) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesViewController.swift index a08929e20a..03348fb459 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/ReleaseNotesViewController.swift @@ -1,15 +1,15 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class ReleaseNotesViewController: MarkdownViewController { private let urlManager: UrlManager private let presented: Bool - private let closeHandler: (() -> ())? + private let closeHandler: (() -> Void)? let bottomHolder = UIView() - init(viewModel: MarkdownViewModel, handleRelativeUrl: Bool, urlManager: UrlManager, presented: Bool, closeHandler: (() -> ())? = nil) { + init(viewModel: MarkdownViewModel, handleRelativeUrl: Bool, urlManager: UrlManager, presented: Bool, closeHandler: (() -> Void)? = nil) { self.urlManager = urlManager self.presented = presented self.closeHandler = closeHandler @@ -19,7 +19,8 @@ class ReleaseNotesViewController: MarkdownViewController { navigationItem.largeTitleDisplayMode = .automatic } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -119,13 +120,10 @@ class ReleaseNotesViewController: MarkdownViewController { @objc private func onRedditTap() { urlManager.open(url: "https://www.reddit.com/r/\(AppConfig.appRedditAccount)", from: nil) } - } extension ReleaseNotesViewController: UIAdaptivePresentationControllerDelegate { - - func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + func presentationControllerDidDismiss(_: UIPresentationController) { closeHandler?() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/Workers/SendAppShowWorker/AddressAppShowModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/Workers/SendAppShowWorker/AddressAppShowModule.swift index 56e962a9c1..e653acf31c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/Workers/SendAppShowWorker/AddressAppShowModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/Workers/SendAppShowWorker/AddressAppShowModule.swift @@ -1,6 +1,6 @@ +import MarketKit import RxSwift import UIKit -import MarketKit class AddressAppShowModule { private let disposeBag = DisposeBag() @@ -18,8 +18,8 @@ class AddressAppShowModule { let abstractParser = AddressUriParser(blockchainType: nil, tokenType: nil) let result = abstractParser.parse(addressUri: text) switch result { - case .uri(let uri): - guard BlockchainType.supported.map({ $0.uriScheme }).contains(uri.scheme) else { + case let .uri(uri): + guard BlockchainType.supported.map(\.uriScheme).contains(uri.scheme) else { return nil } return uri @@ -29,18 +29,17 @@ class AddressAppShowModule { private func showSendTokenList(uri: AddressUri, allowedBlockchainTypes: [BlockchainType]?, allowedTokenTypes: [TokenType]?) { guard let viewController = WalletModule.sendTokenListViewController( - allowedBlockchainTypes: allowedBlockchainTypes, - allowedTokenTypes: allowedTokenTypes, - mode: .prefilled(address: uri.address, amount: uri.amount)) else { + allowedBlockchainTypes: allowedBlockchainTypes, + allowedTokenTypes: allowedTokenTypes, + mode: .prefilled(address: uri.address, amount: uri.amount) + ) else { return } parentViewController?.visibleController.present(viewController, animated: true) } - } extension AddressAppShowModule: IEventHandler { - @MainActor func handle(event: Any, eventType: EventHandler.EventType) async throws { guard eventType.contains(.address) else { @@ -58,8 +57,8 @@ extension AddressAppShowModule: IEventHandler { var allowedTokenTypes: [TokenType]? if let tokenUid: String = uri.value(field: .tokenUid), - let tokenType = TokenType(id: tokenUid) { - + let tokenType = TokenType(id: tokenUid) + { allowedTokenTypes = [tokenType] } @@ -71,7 +70,7 @@ extension AddressAppShowModule: IEventHandler { chain .handlers(address: text) .subscribe(onSuccess: { items in - continuation.resume(returning: items.map { $0.blockchainType }) + continuation.resume(returning: items.map(\.blockchainType)) }, onError: { error in continuation.resume(throwing: error) }) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressModule.swift index e5bd4c6ef1..5d2c8e7272 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressModule.swift @@ -1,7 +1,6 @@ import UIKit struct EvmAddressModule { - static func viewController(accountType: AccountType) -> UIViewController? { guard let service = EvmAddressService(accountType: accountType, evmBlockchainManager: App.shared.evmBlockchainManager) else { return nil @@ -10,5 +9,4 @@ struct EvmAddressModule { let viewModel = EvmAddressViewModel(service: service) return EvmAddressViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressService.swift index bd3c00961d..391abc06af 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressService.swift @@ -8,17 +8,17 @@ class EvmAddressService { switch accountType { case .mnemonic: guard let seed = accountType.mnemonicSeed, - let address = try? Signer.address(seed: seed, chain: evmBlockchainManager.chain(blockchainType: .ethereum)).eip55 else { + let address = try? Signer.address(seed: seed, chain: evmBlockchainManager.chain(blockchainType: .ethereum)).eip55 + else { return nil } self.address = address - case .evmPrivateKey(let data): + case let .evmPrivateKey(data): address = Signer.address(privateKey: data).eip55 - case .evmAddress(let address): + case let .evmAddress(address): self.address = address.eip55 default: return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewController.swift index 2da19135b9..669facee71 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView import ComponentKit +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class EvmAddressViewController: ThemeViewController { private let viewModel: EvmAddressViewModel @@ -15,7 +15,8 @@ class EvmAddressViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -64,11 +65,9 @@ class EvmAddressViewController: ThemeViewController { UIPasteboard.general.string = viewModel.address HudHelper.instance.show(banner: .copied) } - } extension EvmAddressViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { let address = viewModel.address @@ -77,38 +76,37 @@ extension EvmAddressViewController: SectionsDataSource { return [ Section( - id: "main", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - CellBuilderNew.row( - rootElement: .text { component in - component.font = textFont - component.textColor = .themeLeah - component.text = address - component.numberOfLines = 0 - }, - layoutMargins: UIEdgeInsets(top: 0, left: .margin24, bottom: 0, right: .margin24), - tableView: tableView, - id: "address", - dynamicHeight: { width in - CellBuilderNew.height( - containerWidth: width, - backgroundStyle: backgroundStyle, - text: address, - font: textFont, - verticalPadding: .margin24, - elements: [.multiline] - ) - }, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, cornerRadius: .cornerRadius24, isFirst: true, isLast: true) - cell.selectionStyle = .none - } - ) - ] - ) + id: "main", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + CellBuilderNew.row( + rootElement: .text { component in + component.font = textFont + component.textColor = .themeLeah + component.text = address + component.numberOfLines = 0 + }, + layoutMargins: UIEdgeInsets(top: 0, left: .margin24, bottom: 0, right: .margin24), + tableView: tableView, + id: "address", + dynamicHeight: { width in + CellBuilderNew.height( + containerWidth: width, + backgroundStyle: backgroundStyle, + text: address, + font: textFont, + verticalPadding: .margin24, + elements: [.multiline] + ) + }, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, cornerRadius: .cornerRadius24, isFirst: true, isLast: true) + cell.selectionStyle = .none + } + ), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewModel.swift index 05cef34140..eba0ccb56d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/EvmAddress/EvmAddressViewModel.swift @@ -4,13 +4,10 @@ class EvmAddressViewModel { init(service: EvmAddressService) { self.service = service } - } extension EvmAddressViewModel { - var address: String { service.address } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/ManageAccountViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/ManageAccountViewController.swift index 9a8a124b5d..1be5632baf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/ManageAccountViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/ManageAccountViewController.swift @@ -303,7 +303,7 @@ extension ManageAccountViewController: SectionsDataSource { ), ] - if let warningViewItem = warningViewItem { + if let warningViewItem { sections.append( Section( id: "migration-warning", diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PrivateKeys/PrivateKeysViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PrivateKeys/PrivateKeysViewModel.swift index 3d2fc3a4c7..bce7085896 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PrivateKeys/PrivateKeysViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PrivateKeys/PrivateKeysViewModel.swift @@ -1,12 +1,12 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class PrivateKeysViewModel { private let service: PrivateKeysService - private let openUnlockRelay = PublishRelay<()>() + private let openUnlockRelay = PublishRelay() private let openEvmPrivateKeyRelay = PublishRelay() private let openBip32RootKeyRelay = PublishRelay() private let openAccountExtendedPrivateKeyRelay = PublishRelay() @@ -16,12 +16,10 @@ class PrivateKeysViewModel { init(service: PrivateKeysService) { self.service = service } - } extension PrivateKeysViewModel { - - var openUnlockSignal: Signal<()> { + var openUnlockSignal: Signal { openUnlockRelay.asSignal() } @@ -83,15 +81,12 @@ extension PrivateKeysViewModel { openAccountExtendedPrivateKeyRelay.accept(service.accountType) } } - } extension PrivateKeysViewModel { - enum UnlockRequest { case evmPrivateKey case bip32RootKey case accountExtendedPrivateKey } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysModule.swift index 63cbfe3242..4c0beeaf66 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysModule.swift @@ -1,11 +1,9 @@ import UIKit struct PublicKeysModule { - static func viewController(account: Account) -> UIViewController { let service = PublicKeysService(account: account) let viewModel = PublicKeysViewModel(service: service) return PublicKeysViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysService.swift index 0a8ba4a457..ed8d46ec40 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysService.swift @@ -4,11 +4,9 @@ class PublicKeysService { init(account: Account) { self.account = account } - } extension PublicKeysService { - var accountType: AccountType { account.type } @@ -26,5 +24,4 @@ extension PublicKeysService { default: return false } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewController.swift index 6ac3c037c1..5a6682022d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewController.swift @@ -1,8 +1,8 @@ -import UIKit +import ComponentKit +import SectionsTableView import SnapKit import ThemeKit -import SectionsTableView -import ComponentKit +import UIKit class PublicKeysViewController: ThemeViewController { private let viewModel: PublicKeysViewModel @@ -15,7 +15,8 @@ class PublicKeysViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -60,60 +61,57 @@ class PublicKeysViewController: ThemeViewController { let viewController = ExtendedKeyModule.viewController(mode: .accountExtendedPublicKey, accountType: viewModel.accountType) navigationController?.pushViewController(viewController, animated: true) } - } extension PublicKeysViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections: [SectionProtocol] = [ Section( - id: "margin", - headerState: .margin(height: .margin12) - ) + id: "margin", + headerState: .margin(height: .margin12) + ), ] if viewModel.showEvmAddress { sections.append( - Section( + Section( + id: "evm-address", + footerState: tableView.sectionFooter(text: "public_keys.evm_address.description".localized), + rows: [ + tableView.universalRow48( id: "evm-address", - footerState: tableView.sectionFooter(text: "public_keys.evm_address.description".localized), - rows: [ - tableView.universalRow48( - id: "evm-address", - title: .body("public_keys.evm_address".localized), - accessoryType: .disclosure, - isFirst: true, - isLast: true - ) { [weak self] in - self?.openEvmAddress() - } - ] - ) + title: .body("public_keys.evm_address".localized), + accessoryType: .disclosure, + isFirst: true, + isLast: true + ) { [weak self] in + self?.openEvmAddress() + }, + ] + ) ) } if viewModel.showAccountExtendedPublicKey { sections.append( - Section( + Section( + id: "account-extended-public-key", + footerState: tableView.sectionFooter(text: "public_keys.account_extended_public_key.description".localized), + rows: [ + tableView.universalRow48( id: "account-extended-public-key", - footerState: tableView.sectionFooter(text: "public_keys.account_extended_public_key.description".localized), - rows: [ - tableView.universalRow48( - id: "account-extended-public-key", - title: .body("public_keys.account_extended_public_key".localized), - accessoryType: .disclosure, - isFirst: true, - isLast: true - ) { [weak self] in - self?.openAccountExtendedPublicKey() - } - ] - ) + title: .body("public_keys.account_extended_public_key".localized), + accessoryType: .disclosure, + isFirst: true, + isLast: true + ) { [weak self] in + self?.openAccountExtendedPublicKey() + }, + ] + ) ) } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewModel.swift index 75df9b3cfd..a83f3e5f03 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccount/PublicKeys/PublicKeysViewModel.swift @@ -6,11 +6,9 @@ class PublicKeysViewModel { init(service: PublicKeysService) { self.service = service } - } extension PublicKeysViewModel { - var accountType: AccountType { service.accountType } @@ -22,5 +20,4 @@ extension PublicKeysViewModel { var showAccountExtendedPublicKey: Bool { service.accountExtendedPublicKeySupported } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsModule.swift index 20d474027c..0c9132ad74 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsModule.swift @@ -1,20 +1,16 @@ import UIKit struct ManageAccountsModule { - static func viewController(mode: Mode, createAccountListener: ICreateAccountListener? = nil) -> UIViewController { let service = ManageAccountsService(accountManager: App.shared.accountManager, cloudBackupManager: App.shared.cloudBackupManager) let viewModel = ManageAccountsViewModel(service: service, mode: mode) return ManageAccountsViewController(viewModel: viewModel, createAccountListener: createAccountListener) } - } extension ManageAccountsModule { - enum Mode { case manage case switcher } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsService.swift index 6053ac1ea2..246b92b61d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsService.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import Combine +import RxRelay +import RxSwift class ManageAccountsService { private let accountManager: AccountManager @@ -23,10 +23,10 @@ class ManageAccountsService { subscribe(disposeBag, accountManager.activeAccountObservable) { [weak self] _ in self?.syncItems() } cloudBackupManager.$oneWalletItems - .sink { [weak self] _ in - self?.syncItems() - } - .store(in: &cancellables) + .sink { [weak self] _ in + self?.syncItems() + } + .store(in: &cancellables) syncItems() } @@ -38,11 +38,9 @@ class ManageAccountsService { return Item(account: account, cloudBackedUp: cloudBackedUp, isActive: account == activeAccount) } } - } extension ManageAccountsService { - var itemsObservable: Observable<[Item]> { itemsRelay.asObservable() } @@ -58,11 +56,9 @@ extension ManageAccountsService { func set(activeAccountId: String) { accountManager.set(activeAccountId: activeAccountId) } - } extension ManageAccountsService { - struct Item { let account: Account let cloudBackedUp: Bool @@ -76,5 +72,4 @@ extension ManageAccountsService { !account.backedUp } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsViewModel.swift index 385a5403c9..1450283ba4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageAccounts/ManageAccountsViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class ManageAccountsViewModel { private let service: ManageAccountsService @@ -8,7 +8,7 @@ class ManageAccountsViewModel { private let disposeBag = DisposeBag() private let viewStateRelay = BehaviorRelay(value: ViewState.empty) - private let finishRelay = PublishRelay<()>() + private let finishRelay = PublishRelay() init(service: ManageAccountsService, mode: ManageAccountsModule.Mode) { self.service = service @@ -23,8 +23,8 @@ class ManageAccountsViewModel { let sortedItems = items.sorted { $0.account.name.lowercased() < $1.account.name.lowercased() } let viewState = ViewState( - regularViewItems: sortedItems.filter { !$0.account.watchAccount }.map { viewItem(item: $0) }, - watchViewItems: sortedItems.filter { $0.account.watchAccount }.map { viewItem(item: $0) } + regularViewItems: sortedItems.filter { !$0.account.watchAccount }.map { viewItem(item: $0) }, + watchViewItems: sortedItems.filter(\.account.watchAccount).map { viewItem(item: $0) } ) viewStateRelay.accept(viewState) @@ -40,25 +40,23 @@ class ManageAccountsViewModel { let showAlert = item.account.nonStandard || item.account.nonRecommended || item.hasAlert return ViewItem( - accountId: item.account.id, - title: item.account.name, - subtitle: alertSubtitle ?? item.account.type.detailedDescription, - isSubtitleWarning: alertSubtitle != nil, - selected: item.isActive, - alert: showAlert, - watchAccount: item.account.watchAccount + accountId: item.account.id, + title: item.account.name, + subtitle: alertSubtitle ?? item.account.type.detailedDescription, + isSubtitleWarning: alertSubtitle != nil, + selected: item.isActive, + alert: showAlert, + watchAccount: item.account.watchAccount ) } - } extension ManageAccountsViewModel { - var viewStateDriver: Driver { viewStateRelay.asDriver() } - var finishSignal: Signal<()> { + var finishSignal: Signal { finishRelay.asSignal() } @@ -81,11 +79,9 @@ extension ManageAccountsViewModel { finishRelay.accept(()) } } - } extension ManageAccountsViewModel { - struct ViewState { let regularViewItems: [ViewItem] let watchViewItems: [ViewItem] @@ -104,5 +100,4 @@ extension ManageAccountsViewModel { let alert: Bool let watchAccount: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsModule.swift index b00d5be81b..0a3e27c4bf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsModule.swift @@ -1,16 +1,15 @@ -import UIKit import ThemeKit +import UIKit struct ManageWalletsModule { - static func viewController() -> UIViewController? { let (restoreSettingsService, restoreSettingsView) = RestoreSettingsModule.module() guard let service = ManageWalletsService( - marketKit: App.shared.marketKit, - walletManager: App.shared.walletManager, - accountManager: App.shared.accountManager, - restoreSettingsService: restoreSettingsService + marketKit: App.shared.marketKit, + walletManager: App.shared.walletManager, + accountManager: App.shared.accountManager, + restoreSettingsService: restoreSettingsService ) else { return nil } @@ -20,5 +19,4 @@ struct ManageWalletsModule { return ThemeNavigationController(rootViewController: viewController) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsService.swift index 5c67da2cae..ae8e98f734 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import MarketKit import EvmKit +import MarketKit +import RxRelay +import RxSwift class ManageWalletsService { private let account: Account @@ -68,10 +68,10 @@ class ManageWalletsService { private func fetchTokens() -> [Token] { do { if filter.trimmingCharacters(in: .whitespaces).isEmpty { - let list = BlockchainType.supported.map { $0.defaultTokenQuery } + let list = BlockchainType.supported.map(\.defaultTokenQuery) let tokens = try marketKit.tokens(queries: list) let featuredTokens = tokens.filter { account.type.supports(token: $0) } - let enabledTokens = wallets.map { $0.token } + let enabledTokens = wallets.map(\.token) return (enabledTokens + featuredTokens).removeDuplicates() } else if let ethAddress = try? EvmKit.Address(hex: filter) { @@ -81,7 +81,7 @@ class ManageWalletsService { return tokens.filter { account.type.supports(token: $0) } } else { let allFullCoins = try marketKit.fullCoins(filter: filter, limit: 100) - let tokens = allFullCoins.map { $0.tokens }.flatMap { $0 } + let tokens = allFullCoins.map(\.tokens).flatMap { $0 } return tokens.filter { account.type.supports(token: $0) } } @@ -162,9 +162,9 @@ class ManageWalletsService { let enabled = isEnabled(token: token) return Item( - token: token, - enabled: enabled, - hasInfo: hasInfo(token: token, enabled: enabled) + token: token, + enabled: enabled, + hasInfo: hasInfo(token: token, enabled: enabled) ) } @@ -189,11 +189,9 @@ class ManageWalletsService { let wallet = Wallet(token: token, account: account) walletManager.save(wallets: [wallet]) } - } extension ManageWalletsService { - var itemsObservable: Observable<[Item]> { itemsRelay.asObservable() } @@ -251,17 +249,15 @@ extension ManageWalletsService { } switch token.type { - case .eip20(let value), .bep2(let value): + case let .eip20(value), let .bep2(value): return InfoItem(token: token, type: .contractAddress(value: value, explorerUrl: token.blockchain.explorerUrl(reference: value))) default: return nil } } - } extension ManageWalletsService { - struct Item { let token: Token let enabled: Bool @@ -279,5 +275,4 @@ extension ManageWalletsService { case birthdayHeight(height: Int) case contractAddress(value: String, explorerUrl: String?) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewController.swift index 15e0fb5585..44c42fa22f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewController.swift @@ -1,11 +1,11 @@ import Combine -import UIKit -import RxSwift -import RxCocoa -import SnapKit import ComponentKit +import RxCocoa +import RxSwift import SectionsTableView +import SnapKit import ThemeKit +import UIKit class ManageWalletsViewController: ThemeSearchViewController { private let viewModel: ManageWalletsViewModel @@ -26,7 +26,8 @@ class ManageWalletsViewController: ThemeSearchViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -71,9 +72,9 @@ class ManageWalletsViewController: ThemeSearchViewController { subscribe(disposeBag, viewModel.showContractSignal) { [weak self] in self?.showContract(viewItem: $0) } $filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } + .store(in: &cancellables) tableView.buildSections() @@ -98,7 +99,7 @@ class ManageWalletsViewController: ThemeSearchViewController { } private func onUpdate(viewItems: [ManageWalletsViewModel.ViewItem]) { - let animated = self.viewItems.map { $0.uid } == viewItems.map { $0.uid } + let animated = self.viewItems.map(\.uid) == viewItems.map(\.uid) self.viewItems = viewItems if isLoaded { @@ -112,28 +113,28 @@ class ManageWalletsViewController: ThemeSearchViewController { private func showInfo(viewItem: ManageWalletsViewModel.InfoViewItem) { showBottomSheet(viewItem: viewItem.coin, items: [ - .description(text: viewItem.text) + .description(text: viewItem.text), ]) } private func showBirthdayHeight(viewItem: ManageWalletsViewModel.BirthdayHeightViewItem) { showBottomSheet(viewItem: viewItem.coin, items: [ - .copyableValue(title: "birthday_height.title".localized, value: viewItem.height) + .copyableValue(title: "birthday_height.title".localized, value: viewItem.height), ]) } private func showContract(viewItem: ManageWalletsViewModel.ContractViewItem) { showBottomSheet(viewItem: viewItem.coin, items: [ - .contractAddress(imageUrl: viewItem.blockchainImageUrl, value: viewItem.value, explorerUrl: viewItem.explorerUrl) + .contractAddress(imageUrl: viewItem.blockchainImageUrl, value: viewItem.value, explorerUrl: viewItem.explorerUrl), ]) } private func showBottomSheet(viewItem: ManageWalletsViewModel.CoinViewItem, items: [BottomSheetModule.Item]) { let viewController = BottomSheetModule.viewController( - image: .remote(url: viewItem.coinImageUrl, placeholder: viewItem.coinPlaceholderImageName), - title: viewItem.coinCode, - subtitle: viewItem.coinName, - items: items + image: .remote(url: viewItem.coinImageUrl, placeholder: viewItem.coinPlaceholderImageName), + title: viewItem.coinCode, + subtitle: viewItem.coinName, + items: items ) present(viewController, animated: true) @@ -154,17 +155,15 @@ class ManageWalletsViewController: ThemeSearchViewController { CellBuilderNew.buildStatic(cell: cell, rootElement: rootElement(index: index, viewItem: viewItems[index], forceToggleOn: on)) } - } extension ManageWalletsViewController: SectionsDataSource { - private func rootElement(index: Int, viewItem: ManageWalletsViewModel.ViewItem, forceToggleOn: Bool? = nil) -> CellBuilderNew.CellElement { .hStack([ .image32 { component in component.setImage( - urlString: viewItem.imageUrl, - placeholder: viewItem.placeholderImageName.flatMap { UIImage(named: $0) } + urlString: viewItem.imageUrl, + placeholder: viewItem.placeholderImageName.flatMap { UIImage(named: $0) } ) }, .vStackCentered([ @@ -177,10 +176,10 @@ extension ManageWalletsViewController: SectionsDataSource { component.badgeView.text = viewItem.badge }, .margin0, - .text { _ in } + .text { _ in }, ]), .margin(1), - .textElement(text: .subhead2(viewItem.subtitle)) + .textElement(text: .subhead2(viewItem.subtitle)), ]), .secondaryCircleButton { [weak self] component in component.isHidden = !viewItem.hasInfo @@ -199,33 +198,32 @@ extension ManageWalletsViewController: SectionsDataSource { component.onSwitch = { [weak self] enabled in self?.onToggle(index: index, enabled: enabled) } - } + }, ]) } func buildSections() -> [SectionProtocol] { [ Section( - id: "coins", - headerState: .margin(height: .margin4), - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - let isLast = index == viewItems.count - 1 - - return CellBuilderNew.row( - rootElement: rootElement(index: index, viewItem: viewItem), - tableView: tableView, - id: "token_\(viewItem.uid)", - hash: "token_\(viewItem.enabled)_\(viewItem.hasInfo)_\(isLast)", - height: .heightDoubleLineCell, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - } - ) - } - ) + id: "coins", + headerState: .margin(height: .margin4), + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + let isLast = index == viewItems.count - 1 + + return CellBuilderNew.row( + rootElement: rootElement(index: index, viewItem: viewItem), + tableView: tableView, + id: "token_\(viewItem.uid)", + hash: "token_\(viewItem.enabled)_\(viewItem.hasInfo)_\(isLast)", + height: .heightDoubleLineCell, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .transparent, isLast: isLast) + } + ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewModel.swift index 6a725d3054..5706102488 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ManageWallets/ManageWalletsViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class ManageWalletsViewModel { private let service: ManageWalletsService @@ -28,14 +28,14 @@ class ManageWalletsViewModel { let token = item.token return ViewItem( - uid: String(item.token.hashValue), - imageUrl: token.coin.imageUrl, - placeholderImageName: token.placeholderImageName, - title: token.coin.code, - subtitle: token.coin.name, - badge: item.token.badge, - enabled: item.enabled, - hasInfo: item.hasInfo + uid: String(item.token.hashValue), + imageUrl: token.coin.imageUrl, + placeholderImageName: token.placeholderImageName, + title: token.coin.code, + subtitle: token.coin.name, + badge: item.token.badge, + enabled: item.enabled, + hasInfo: item.hasInfo ) } @@ -43,11 +43,9 @@ class ManageWalletsViewModel { viewItemsRelay.accept(items.map { viewItem(item: $0) }) notFoundVisibleRelay.accept(items.isEmpty) } - } extension ManageWalletsViewModel { - var viewItemsDriver: Driver<[ViewItem]> { viewItemsRelay.asDriver() } @@ -90,20 +88,19 @@ extension ManageWalletsViewModel { } let coinViewItem = CoinViewItem( - coinImageUrl: infoItem.token.coin.imageUrl, - coinPlaceholderImageName: infoItem.token.placeholderImageName, - coinName: infoItem.token.coin.name, - coinCode: infoItem.token.coin.code + coinImageUrl: infoItem.token.coin.imageUrl, + coinPlaceholderImageName: infoItem.token.placeholderImageName, + coinName: infoItem.token.coin.name, + coinCode: infoItem.token.coin.code ) - switch infoItem.type { case .derivation: let coinName = infoItem.token.coin.name showInfoRelay.accept(InfoViewItem(coin: coinViewItem, text: "manage_wallets.derivation_description".localized(coinName, AppConfig.appName, coinName))) case .bitcoinCashCoinType: showInfoRelay.accept(InfoViewItem(coin: coinViewItem, text: "manage_wallets.bitcoin_cash_coin_type_description".localized(AppConfig.appName))) - case .birthdayHeight(let height): + case let .birthdayHeight(height): showBirthdayHeightRelay.accept(BirthdayHeightViewItem(coin: coinViewItem, height: String(height))) case let .contractAddress(value, explorerUrl): showContractRelay.accept(ContractViewItem(coin: coinViewItem, blockchainImageUrl: infoItem.token.blockchainType.imageUrl, value: value, explorerUrl: explorerUrl)) @@ -115,11 +112,9 @@ extension ManageWalletsViewModel { self?.service.set(filter: filter) } } - } extension ManageWalletsViewModel { - struct ViewItem { let uid: String let imageUrl: String @@ -154,5 +149,4 @@ extension ManageWalletsViewModel { let value: String let explorerUrl: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/AcademyMarkdownConfig.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/AcademyMarkdownConfig.swift index bcafbbc72d..1cb6fb3351 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/AcademyMarkdownConfig.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/AcademyMarkdownConfig.swift @@ -1,15 +1,14 @@ +import Down import Foundation -import UIKit import ThemeKit -import Down +import UIKit struct AcademyMarkdownConfig { - private static let colors = StaticColorCollection( - heading1: .themeLeah, - heading2: .themeJacob, - heading3: .themeJacob, - body: .themeBran + heading1: .themeLeah, + heading2: .themeJacob, + heading3: .themeJacob, + body: .themeBran ) private static let paragraphStyles: StaticParagraphStyleCollection = { @@ -30,17 +29,16 @@ struct AcademyMarkdownConfig { static var config: DownStylerConfiguration { let fonts = StaticFontCollection( - heading1: .title2, - heading2: .title3, - heading3: .headline2, - body: .body + heading1: .title2, + heading2: .title3, + heading3: .headline2, + body: .body ) return DownStylerConfiguration( - fonts: fonts, - colors: colors, - paragraphStyles: paragraphStyles + fonts: fonts, + colors: colors, + paragraphStyles: paragraphStyles ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownBlockQuoteCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownBlockQuoteCell.swift index 71b86cc627..9011103215 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownBlockQuoteCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownBlockQuoteCell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class MarkdownBlockQuoteCell: UITableViewCell { private static let verticalMargin: CGFloat = .margin3x @@ -38,7 +38,8 @@ class MarkdownBlockQuoteCell: UITableViewCell { lineView.backgroundColor = .themeRemus } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -52,11 +53,9 @@ class MarkdownBlockQuoteCell: UITableViewCell { maker.bottom.equalToSuperview().inset(tightBottom ? 0 : MarkdownBlockQuoteCell.verticalMargin) } } - } extension MarkdownBlockQuoteCell { - static func height(containerWidth: CGFloat, attributedString: NSAttributedString, tightTop: Bool, tightBottom: Bool) -> CGFloat { let textWidth = containerWidth - 2 * horizontalPadding let textHeight = attributedString.height(containerWidth: textWidth) @@ -66,5 +65,4 @@ extension MarkdownBlockQuoteCell { return topMargin + textHeight + 2 * verticalPadding + bottomMargin } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader1Cell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader1Cell.swift index a54c022cad..4bcb242627 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader1Cell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader1Cell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class MarkdownHeader1Cell: UITableViewCell { private static let topPadding: CGFloat = .margin6x @@ -34,23 +34,21 @@ class MarkdownHeader1Cell: UITableViewCell { separatorView.backgroundColor = .themeGray50 } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func bind(attributedString: NSAttributedString) { textView.attributedText = attributedString } - } extension MarkdownHeader1Cell { - static func height(containerWidth: CGFloat, attributedString: NSAttributedString) -> CGFloat { let textWidth = containerWidth - 2 * horizontalPadding let textHeight = attributedString.height(containerWidth: textWidth) return topPadding + textHeight + separatorTopMargin + separatorHeight + bottomPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader3Cell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader3Cell.swift index e8dee3bba4..2d96b270cd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader3Cell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownHeader3Cell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class MarkdownHeader3Cell: UITableViewCell { private static let topPadding: CGFloat = .margin6x @@ -22,23 +22,21 @@ class MarkdownHeader3Cell: UITableViewCell { } } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func bind(attributedString: NSAttributedString) { textView.attributedText = attributedString } - } extension MarkdownHeader3Cell { - static func height(containerWidth: CGFloat, attributedString: NSAttributedString) -> CGFloat { let textWidth = containerWidth - 2 * horizontalPadding let textHeight = attributedString.height(containerWidth: textWidth) return topPadding + textHeight + bottomPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageCell.swift index b784154df7..85b8c6d58e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageCell.swift @@ -1,7 +1,7 @@ -import UIKit +import Kingfisher import SnapKit import ThemeKit -import Kingfisher +import UIKit class MarkdownImageCell: UITableViewCell { private static let verticalPadding: CGFloat = .margin3x @@ -32,11 +32,12 @@ class MarkdownImageCell: UITableViewCell { markdownImageView.clipsToBounds = true } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - func bind(imageUrl: URL, type: MarkdownImageType, tight: Bool) { + func bind(imageUrl: URL, type _: MarkdownImageType, tight: Bool) { placeholderImageView.isHidden = false markdownImageView.kf.setImage(with: imageUrl) { [weak self] result in @@ -51,11 +52,9 @@ class MarkdownImageCell: UITableViewCell { maker.top.bottom.equalToSuperview().inset(tight ? 0 : MarkdownImageCell.verticalPadding) } } - } extension MarkdownImageCell { - static func height(containerWidth: CGFloat, type: MarkdownImageType, tight: Bool) -> CGFloat { var imageHeight: CGFloat @@ -71,5 +70,4 @@ extension MarkdownImageCell { return imageHeight } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageTitleCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageTitleCell.swift index d1b8bb3520..46598c8e9a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageTitleCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownImageTitleCell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class MarkdownImageTitleCell: UITableViewCell { private static let verticalPadding: CGFloat = .margin3x @@ -25,22 +25,20 @@ class MarkdownImageTitleCell: UITableViewCell { label.textColor = .themeGray } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func bind(text: String) { label.text = text } - } extension MarkdownImageTitleCell { - static func height(containerWidth: CGFloat, text: String) -> CGFloat { let textWidth = containerWidth - 2 * horizontalPadding let textHeight = text.height(forContainerWidth: textWidth, font: labelFont) return textHeight + 2 * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownListItemCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownListItemCell.swift index 28141e17b1..6e37bc8b21 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownListItemCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownListItemCell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class MarkdownListItemCell: UITableViewCell { private static let horizontalPadding: CGFloat = .margin6x @@ -39,7 +39,8 @@ class MarkdownListItemCell: UITableViewCell { } } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -54,11 +55,9 @@ class MarkdownListItemCell: UITableViewCell { maker.bottom.equalToSuperview().inset(tightBottom ? MarkdownListItemCell.tightVerticalPadding : MarkdownListItemCell.verticalPadding) } } - } extension MarkdownListItemCell { - static func height(containerWidth: CGFloat, attributedString: NSAttributedString, tightTop: Bool, tightBottom: Bool) -> CGFloat { let textWidth = containerWidth - prefixWidth - 2 * horizontalPadding let textHeight = attributedString.height(containerWidth: textWidth) @@ -67,5 +66,4 @@ extension MarkdownListItemCell { return topPadding + textHeight + bottomPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownTextCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownTextCell.swift index 7a87f1e255..ef9ec81ed4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownTextCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Cells/MarkdownTextCell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class MarkdownTextCell: UITableViewCell { private static let verticalPadding: CGFloat = .margin3x @@ -20,7 +20,8 @@ class MarkdownTextCell: UITableViewCell { } } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -28,16 +29,13 @@ class MarkdownTextCell: UITableViewCell { textView.attributedText = attributedString textView.delegate = delegate } - } extension MarkdownTextCell { - static func height(containerWidth: CGFloat, attributedString: NSAttributedString) -> CGFloat { let textWidth = containerWidth - 2 * horizontalPadding let textHeight = attributedString.height(containerWidth: textWidth) return textHeight + 2 * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Components/MarkdownTextView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Components/MarkdownTextView.swift index 59c5f2563f..e708fc30ca 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Components/MarkdownTextView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/Components/MarkdownTextView.swift @@ -1,8 +1,7 @@ -import UIKit import ThemeKit +import UIKit class MarkdownTextView: UITextView { - init() { super.init(frame: .zero, textContainer: nil) @@ -15,12 +14,12 @@ class MarkdownTextView: UITextView { linkTextAttributes = [ .foregroundColor: UIColor.themeJacob, .underlineColor: UIColor.themeJacob, - .underlineStyle: NSUnderlineStyle.single.rawValue + .underlineStyle: NSUnderlineStyle.single.rawValue, ] } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownContentProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownContentProvider.swift index 507d60eb7d..d974783698 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownContentProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownContentProvider.swift @@ -1,7 +1,7 @@ +import Alamofire import Foundation -import RxSwift import HsToolKit -import Alamofire +import RxSwift protocol IMarkdownContentProvider { var contentSingle: Single { get } @@ -23,9 +23,9 @@ class MarkdownPlainContentProvider: IMarkdownContentProvider { return Single.create { observer in let requestReference = request.responseString(queue: DispatchQueue.global(qos: .background)) { response in switch response.result { - case .success(let result): + case let .success(result): observer(.success(result)) - case .failure(let error): + case let .failure(error): observer(.error(NetworkManager.unwrap(error: error))) } } @@ -39,7 +39,6 @@ class MarkdownPlainContentProvider: IMarkdownContentProvider { var markdownUrl: URL? { url } - } class MarkdownGitReleaseContentProvider: IMarkdownContentProvider { @@ -60,11 +59,9 @@ class MarkdownGitReleaseContentProvider: IMarkdownContentProvider { var markdownUrl: URL? { nil } - } extension MarkdownGitReleaseContentProvider: IApiMapper { - public func map(statusCode: Int, data: Any?) throws -> String { guard let map = data as? [String: Any] else { throw NetworkManager.RequestError.invalidResponse(statusCode: statusCode, data: data) @@ -76,5 +73,4 @@ extension MarkdownGitReleaseContentProvider: IApiMapper { return result } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownParser.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownParser.swift index 65a0e21f30..474aaec98d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownParser.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownParser.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import Down +import ThemeKit +import UIKit class MarkdownParser { - func viewItems(content: String, url: URL?, configuration: DownStylerConfiguration) -> [MarkdownBlockViewItem] { let down = Down(markdownString: content) @@ -46,10 +45,10 @@ class MarkdownParser { for (paragraphIndex, paragraphBlock) in itemBlock.paragraphBlocks.enumerated() { viewItems.append(.listItem( - attributedString: paragraphBlock.attributedString, - prefix: paragraphIndex == 0 ? prefix : nil, - tightTop: listBlock.tight && itemIndex != 0, - tightBottom: listBlock.tight && itemIndex != listBlock.itemBlocks.count - 1 + attributedString: paragraphBlock.attributedString, + prefix: paragraphIndex == 0 ? prefix : nil, + tightTop: listBlock.tight && itemIndex != 0, + tightBottom: listBlock.tight && itemIndex != listBlock.itemBlocks.count - 1 )) } @@ -60,9 +59,9 @@ class MarkdownParser { if let blockQuoteBlock = block as? MarkdownVisitor.BlockQuoteBlock { for (paragraphIndex, paragraphBlock) in blockQuoteBlock.paragraphBlocks.enumerated() { viewItems.append(.blockQuote( - attributedString: paragraphBlock.attributedString, - tightTop: paragraphIndex != 0, - tightBottom: paragraphIndex != blockQuoteBlock.paragraphBlocks.count - 1 + attributedString: paragraphBlock.attributedString, + tightTop: paragraphIndex != 0, + tightBottom: paragraphIndex != blockQuoteBlock.paragraphBlocks.count - 1 )) } } @@ -91,5 +90,4 @@ class MarkdownParser { return [] } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownService.swift index a965c19e73..f9dcb04dcd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownService.swift @@ -1,8 +1,8 @@ +import Alamofire import Foundation -import RxSwift -import RxRelay import HsToolKit -import Alamofire +import RxRelay +import RxSwift class MarkdownService { private let provider: IMarkdownContentProvider @@ -23,17 +23,15 @@ class MarkdownService { private func fetchContent() { provider.contentSingle - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] content in - self?.content = content - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] content in + self?.content = content + }) + .disposed(by: disposeBag) } - } extension MarkdownService { - var contentObservable: Observable { contentRelay.asObservable() } @@ -41,5 +39,4 @@ extension MarkdownService { var markdownUrl: URL? { provider.markdownUrl } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewController.swift index 6b7d247570..474896ab4b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import SnapKit -import ThemeKit -import SectionsTableView import HUD -import RxSwift import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class MarkdownViewController: ThemeViewController { private let viewModel: MarkdownViewModel @@ -26,7 +26,8 @@ class MarkdownViewController: ThemeViewController { navigationItem.largeTitleDisplayMode = .never } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -96,52 +97,50 @@ class MarkdownViewController: ThemeViewController { switch viewItem { case let .header(attributedString, level): return Self.headerRow( - id: "header_\(index)", - attributedString: attributedString, - level: level + id: "header_\(index)", + attributedString: attributedString, + level: level ) case let .text(attributedString): return Self.textRow( - id: "text_\(index)", - attributedString: attributedString, - delegate: self + id: "text_\(index)", + attributedString: attributedString, + delegate: self ) case let .listItem(attributedString, prefix, tightTop, tightBottom): return Self.listItemRow( - id: "listItem_\(index)", - attributedString: attributedString, - prefix: prefix, - tightTop: tightTop, - tightBottom: tightBottom, - delegate: self + id: "listItem_\(index)", + attributedString: attributedString, + prefix: prefix, + tightTop: tightTop, + tightBottom: tightBottom, + delegate: self ) case let .blockQuote(attributedString, tightTop, tightBottom): return Self.blockQuoteRow( - id: "blockQuote_\(index)", - attributedString: attributedString, - tightTop: tightTop, - tightBottom: tightBottom, - delegate: self + id: "blockQuote_\(index)", + attributedString: attributedString, + tightTop: tightTop, + tightBottom: tightBottom, + delegate: self ) case let .image(url, type, tight): return Self.imageRow( - id: "image_\(index)", - url: url, - type: type, - tight: tight + id: "image_\(index)", + url: url, + type: type, + tight: tight ) case let .imageTitle(text): return Self.imageTitleRow( - id: "imageTitle_\(index)", - text: text + id: "imageTitle_\(index)", + text: text ) } } - } extension MarkdownViewController { - static func header1Row(id: String, string: String) -> RowProtocol { header1Row(id: id, attributedString: NSAttributedString(string: string, attributes: [.font: UIFont.title2, .foregroundColor: UIColor.themeLeah])) } @@ -156,11 +155,11 @@ extension MarkdownViewController { static func listItemRow(id: String, string: String) -> RowProtocol { listItemRow( - id: id, - attributedString: NSAttributedString(string: string, attributes: [.font: UIFont.body, .foregroundColor: UIColor.themeBran]), - prefix: "•", - tightTop: false, - tightBottom: false + id: id, + attributedString: NSAttributedString(string: string, attributes: [.font: UIFont.body, .foregroundColor: UIColor.themeBran]), + prefix: "•", + tightTop: false, + tightBottom: false ) } @@ -174,94 +173,92 @@ extension MarkdownViewController { static func header1Row(id: String, attributedString: NSAttributedString) -> RowProtocol { Row( - id: id, - dynamicHeight: { containerWidth in - MarkdownHeader1Cell.height(containerWidth: containerWidth, attributedString: attributedString) - }, - bind: { cell, _ in - cell.bind(attributedString: attributedString) - } + id: id, + dynamicHeight: { containerWidth in + MarkdownHeader1Cell.height(containerWidth: containerWidth, attributedString: attributedString) + }, + bind: { cell, _ in + cell.bind(attributedString: attributedString) + } ) } static func header3Row(id: String, attributedString: NSAttributedString) -> RowProtocol { Row( - id: id, - dynamicHeight: { containerWidth in - MarkdownHeader3Cell.height(containerWidth: containerWidth, attributedString: attributedString) - }, - bind: { cell, _ in - cell.bind(attributedString: attributedString) - } + id: id, + dynamicHeight: { containerWidth in + MarkdownHeader3Cell.height(containerWidth: containerWidth, attributedString: attributedString) + }, + bind: { cell, _ in + cell.bind(attributedString: attributedString) + } ) } static func textRow(id: String, attributedString: NSAttributedString, delegate: UITextViewDelegate? = nil) -> RowProtocol { Row( - id: id, - dynamicHeight: { containerWidth in - MarkdownTextCell.height(containerWidth: containerWidth, attributedString: attributedString) - }, - bind: { [weak delegate] cell, _ in - cell.bind(attributedString: attributedString, delegate: delegate) - } + id: id, + dynamicHeight: { containerWidth in + MarkdownTextCell.height(containerWidth: containerWidth, attributedString: attributedString) + }, + bind: { [weak delegate] cell, _ in + cell.bind(attributedString: attributedString, delegate: delegate) + } ) } static func listItemRow(id: String, attributedString: NSAttributedString, prefix: String?, tightTop: Bool, tightBottom: Bool, delegate: UITextViewDelegate? = nil) -> RowProtocol { Row( - id: id, - dynamicHeight: { containerWidth in - MarkdownListItemCell.height(containerWidth: containerWidth, attributedString: attributedString, tightTop: tightTop, tightBottom: tightBottom) - }, - bind: { [weak delegate] cell, _ in - cell.bind(attributedString: attributedString, delegate: delegate, prefix: prefix, tightTop: tightTop, tightBottom: tightBottom) - } + id: id, + dynamicHeight: { containerWidth in + MarkdownListItemCell.height(containerWidth: containerWidth, attributedString: attributedString, tightTop: tightTop, tightBottom: tightBottom) + }, + bind: { [weak delegate] cell, _ in + cell.bind(attributedString: attributedString, delegate: delegate, prefix: prefix, tightTop: tightTop, tightBottom: tightBottom) + } ) } static func blockQuoteRow(id: String, attributedString: NSAttributedString, tightTop: Bool, tightBottom: Bool, delegate: UITextViewDelegate? = nil) -> RowProtocol { Row( - id: id, - dynamicHeight: { containerWidth in - MarkdownBlockQuoteCell.height(containerWidth: containerWidth, attributedString: attributedString, tightTop: tightTop, tightBottom: tightBottom) - }, - bind: { [weak delegate] cell, _ in - cell.bind(attributedString: attributedString, delegate: delegate, tightTop: tightTop, tightBottom: tightBottom) - } + id: id, + dynamicHeight: { containerWidth in + MarkdownBlockQuoteCell.height(containerWidth: containerWidth, attributedString: attributedString, tightTop: tightTop, tightBottom: tightBottom) + }, + bind: { [weak delegate] cell, _ in + cell.bind(attributedString: attributedString, delegate: delegate, tightTop: tightTop, tightBottom: tightBottom) + } ) } static func imageRow(id: String, url: URL, type: MarkdownImageType, tight: Bool) -> RowProtocol { Row( - id: id, - dynamicHeight: { containerWidth in - MarkdownImageCell.height(containerWidth: containerWidth, type: type, tight: tight) - }, - bind: { cell, _ in - cell.bind(imageUrl: url, type: type, tight: tight) - } + id: id, + dynamicHeight: { containerWidth in + MarkdownImageCell.height(containerWidth: containerWidth, type: type, tight: tight) + }, + bind: { cell, _ in + cell.bind(imageUrl: url, type: type, tight: tight) + } ) } static func imageTitleRow(id: String, text: String) -> RowProtocol { Row( - id: id, - dynamicHeight: { containerWidth in - MarkdownImageTitleCell.height(containerWidth: containerWidth, text: text) - }, - bind: { cell, _ in - cell.bind(text: text) - } + id: id, + dynamicHeight: { containerWidth in + MarkdownImageTitleCell.height(containerWidth: containerWidth, text: text) + }, + bind: { cell, _ in + cell.bind(text: text) + } ) } - } extension MarkdownViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { - guard let viewItems = viewItems else { + guard let viewItems else { return [] } @@ -269,32 +266,30 @@ extension MarkdownViewController: SectionsDataSource { return [ Section( - id: "blocks", - rows: viewItems.enumerated().map { row(index: $0, viewItem: $1) } + id: "blocks", + rows: viewItems.enumerated().map { row(index: $0, viewItem: $1) } ), Section( - id: "brand", - headerState: .margin(height: .margin32), - rows: [ - Row( - id: "brand", - dynamicHeight: { containerWidth in - BrandFooterCell.height(containerWidth: containerWidth, title: footerText) - }, - bind: { cell, _ in - cell.title = footerText - } - ) - ] - ) + id: "brand", + headerState: .margin(height: .margin32), + rows: [ + Row( + id: "brand", + dynamicHeight: { containerWidth in + BrandFooterCell.height(containerWidth: containerWidth, title: footerText) + }, + bind: { cell, _ in + cell.title = footerText + } + ), + ] + ), ] } - } extension MarkdownViewController: UITextViewDelegate { - - public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + public func textView(_: UITextView, shouldInteractWith URL: URL, in _: NSRange, interaction _: UITextItemInteraction) -> Bool { guard handleRelativeUrl, URL.pathExtension == "md" else { return true } @@ -303,5 +298,4 @@ extension MarkdownViewController: UITextViewDelegate { return false } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewModel.swift index 8c339918a6..9495dd0291 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownViewModel.swift @@ -1,8 +1,8 @@ +import Down import Foundation -import RxSwift -import RxRelay import RxCocoa -import Down +import RxRelay +import RxSwift class MarkdownViewModel { private let service: MarkdownService @@ -22,11 +22,11 @@ class MarkdownViewModel { sync(content: service.content) service.contentObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] content in - self?.sync(content: content) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] content in + self?.sync(content: content) + }) + .disposed(by: disposeBag) } private func sync(content: String?) { @@ -34,11 +34,9 @@ class MarkdownViewModel { viewItemsRelay.accept(content.map { parser.viewItems(content: $0, url: service.markdownUrl, configuration: parserConfig) }) } - } extension MarkdownViewModel { - var loadingDriver: Driver { loadingRelay.asDriver() } @@ -58,5 +56,4 @@ extension MarkdownViewModel { openUrlRelay.accept(resolvedUrl) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownVisitor.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownVisitor.swift index 9c5880465e..6e38620ed5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownVisitor.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Markdown/MarkdownVisitor.swift @@ -1,6 +1,6 @@ -import UIKit import Down import libcmark +import UIKit protocol MarkdownBlock: CustomStringConvertible {} @@ -12,7 +12,6 @@ class MarkdownVisitor { self.attributedStringVisitor = attributedStringVisitor self.styler = styler } - } extension MarkdownVisitor: Visitor { @@ -29,7 +28,7 @@ extension MarkdownVisitor: Visitor { public func visit(list node: List) -> MarkdownBlock { var startOrder: Int? - if case .ordered(let start) = node.listType { + if case let .ordered(start) = node.listType { startOrder = start } @@ -40,15 +39,15 @@ extension MarkdownVisitor: Visitor { ItemBlock(blocks: visitChildren(of: node)) } - public func visit(codeBlock node: CodeBlock) -> MarkdownBlock { + public func visit(codeBlock _: CodeBlock) -> MarkdownBlock { UnhandledBlock(type: "CodeBlock") } - public func visit(htmlBlock node: HtmlBlock) -> MarkdownBlock { + public func visit(htmlBlock _: HtmlBlock) -> MarkdownBlock { UnhandledBlock(type: "HtmlBlock") } - public func visit(customBlock node: CustomBlock) -> MarkdownBlock { + public func visit(customBlock _: CustomBlock) -> MarkdownBlock { UnhandledBlock(type: "CustomBlock") } @@ -69,61 +68,58 @@ extension MarkdownVisitor: Visitor { return HeadingBlock(attributedString: s, level: node.headingLevel) } - public func visit(thematicBreak node: ThematicBreak) -> MarkdownBlock { + public func visit(thematicBreak _: ThematicBreak) -> MarkdownBlock { UnhandledBlock(type: "ThematicBreak") } - public func visit(text node: Text) -> MarkdownBlock { + public func visit(text _: Text) -> MarkdownBlock { UnhandledBlock(type: "Text") } - public func visit(softBreak node: SoftBreak) -> MarkdownBlock { + public func visit(softBreak _: SoftBreak) -> MarkdownBlock { UnhandledBlock(type: "SoftBreak") } - public func visit(lineBreak node: LineBreak) -> MarkdownBlock { + public func visit(lineBreak _: LineBreak) -> MarkdownBlock { UnhandledBlock(type: "LineBreak") } - public func visit(code node: Code) -> MarkdownBlock { + public func visit(code _: Code) -> MarkdownBlock { UnhandledBlock(type: "Code") } - public func visit(htmlInline node: HtmlInline) -> MarkdownBlock { + public func visit(htmlInline _: HtmlInline) -> MarkdownBlock { UnhandledBlock(type: "HtmlInline") } - public func visit(customInline node: CustomInline) -> MarkdownBlock { + public func visit(customInline _: CustomInline) -> MarkdownBlock { UnhandledBlock(type: "CustomInline") } - public func visit(emphasis node: Emphasis) -> MarkdownBlock { + public func visit(emphasis _: Emphasis) -> MarkdownBlock { UnhandledBlock(type: "Emphasis") } - public func visit(strong node: Strong) -> MarkdownBlock { + public func visit(strong _: Strong) -> MarkdownBlock { UnhandledBlock(type: "Strong") } - public func visit(link node: Link) -> MarkdownBlock { + public func visit(link _: Link) -> MarkdownBlock { UnhandledBlock(type: "Link") } public func visit(image node: Image) -> MarkdownBlock { ImageBlock(title: node.title, url: node.url) } - } extension MarkdownVisitor { - struct DocumentBlock: MarkdownBlock { let blocks: [MarkdownBlock] var description: String { "DocumentBlock: \(blocks.count) blocks:\n\(blocks.map { "\($0)" }.joined(separator: "\n"))\n\n" } - } struct HeadingBlock: MarkdownBlock { @@ -133,7 +129,6 @@ extension MarkdownVisitor { var description: String { "Heading Block: level: \(level): \(attributedString.string)" } - } struct ParagraphBlock: MarkdownBlock { @@ -142,7 +137,6 @@ extension MarkdownVisitor { var description: String { "Paragraph Block: \(attributedString.string)" } - } struct ImageBlock: MarkdownBlock { @@ -152,7 +146,6 @@ extension MarkdownVisitor { var description: String { "Image Block: title: \(title ?? "nil"), url: \(url ?? "nil")" } - } struct ListBlock: MarkdownBlock { @@ -167,7 +160,6 @@ extension MarkdownVisitor { var description: String { "List Block: [tight=\(tight), startOrder=\(startOrder.map { "\($0)" } ?? "nil")] \(blocks.count) blocks:\n\(blocks.map { "\($0)" }.joined(separator: "\n"))\n\n" } - } struct ItemBlock: MarkdownBlock { @@ -180,7 +172,6 @@ extension MarkdownVisitor { var description: String { "Item Block: \(blocks.count) block(s)" } - } struct BlockQuoteBlock: MarkdownBlock { @@ -193,7 +184,6 @@ extension MarkdownVisitor { var description: String { "BlockQuote Block: \(blocks.count) block(s)" } - } struct UnhandledBlock: MarkdownBlock { @@ -202,15 +192,11 @@ extension MarkdownVisitor { var description: String { "Unhandled Block: \(type)" } - } - } private extension Sequence where Iterator.Element == NSMutableAttributedString { - var joined: NSMutableAttributedString { reduce(into: NSMutableAttributedString()) { $0.append($1) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchModule.swift index 279a9b5188..f62fc0ef53 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchModule.swift @@ -1,12 +1,10 @@ import UIKit class MarketAdvancedSearchModule { - static func viewController() -> UIViewController { let service = MarketAdvancedSearchService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager) let viewModel = MarketAdvancedSearchViewModel(service: service) return MarketAdvancedSearchViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchService.swift index 4391b66b6a..358d57bef3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchService.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift class MarketAdvancedSearchService { private let blockchainTypes: [BlockchainType] = [ @@ -180,7 +180,7 @@ class MarketAdvancedSearchService { self.currencyManager = currencyManager do { - let blockchains = try marketKit.blockchains(uids: blockchainTypes.map { $0.uid }) + let blockchains = try marketKit.blockchains(uids: blockchainTypes.map(\.uid)) allBlockchains = blockchainTypes.compactMap { type in blockchains.first(where: { $0.type == type }) } } catch { allBlockchains = [] @@ -208,15 +208,15 @@ class MarketAdvancedSearchService { switch internalState { case .loading: state = .loading - case .loaded(let marketInfos): + case let .loaded(marketInfos): state = .loaded(marketInfos: filtered(marketInfos: marketInfos)) - case .failed(let error): + case let .failed(error): state = .failed(error: error) } } private func marketInfo(coinUid: String) -> MarketInfo? { - guard case .loaded(let marketInfos) = internalState else { + guard case let .loaded(marketInfos) = internalState else { return nil } @@ -224,7 +224,7 @@ class MarketAdvancedSearchService { } private func inBounds(value: Decimal?, lower: Decimal, upper: Decimal) -> Bool { - guard let value = value else { + guard let value else { return false } @@ -233,8 +233,9 @@ class MarketAdvancedSearchService { private func outperformed(value: Decimal?, coinUid: String) -> Bool { guard let marketInfo = marketInfo(coinUid: coinUid), - let value = value, - let priceChangeValue = marketInfo.priceChangeValue(type: priceChangeType) else { + let value, + let priceChangeValue = marketInfo.priceChangeValue(type: priceChangeType) + else { return false } @@ -242,7 +243,7 @@ class MarketAdvancedSearchService { } private func closedToAllTime(value: Decimal?) -> Bool { - guard let value = value else { + guard let value else { return false } @@ -254,7 +255,7 @@ class MarketAdvancedSearchService { return true } - guard let tokens = tokens else { + guard let tokens else { return false } @@ -272,21 +273,19 @@ class MarketAdvancedSearchService { let priceChangeValue = marketInfo.priceChangeValue(type: priceChangeType) return inBounds(value: marketInfo.marketCap, lower: marketCap.lowerBound, upper: marketCap.upperBound) && - inBounds(value: marketInfo.totalVolume, lower: volume.lowerBound, upper: volume.upperBound) && - inBlockchain(tokens: marketInfo.fullCoin.tokens) && - inBounds(value: priceChangeValue, lower: priceChange.lowerBound, upper: priceChange.upperBound) && - (!outperformedBtc || outperformed(value: priceChangeValue, coinUid: "bitcoin")) && - (!outperformedEth || outperformed(value: priceChangeValue, coinUid: "ethereum")) && - (!outperformedBnb || outperformed(value: priceChangeValue, coinUid: "binancecoin")) && - (!priceCloseToAth || closedToAllTime(value: marketInfo.athPercentage)) && - (!priceCloseToAtl || closedToAllTime(value: marketInfo.atlPercentage)) + inBounds(value: marketInfo.totalVolume, lower: volume.lowerBound, upper: volume.upperBound) && + inBlockchain(tokens: marketInfo.fullCoin.tokens) && + inBounds(value: priceChangeValue, lower: priceChange.lowerBound, upper: priceChange.upperBound) && + (!outperformedBtc || outperformed(value: priceChangeValue, coinUid: "bitcoin")) && + (!outperformedEth || outperformed(value: priceChangeValue, coinUid: "ethereum")) && + (!outperformedBnb || outperformed(value: priceChangeValue, coinUid: "binancecoin")) && + (!priceCloseToAth || closedToAllTime(value: marketInfo.athPercentage)) && + (!priceCloseToAtl || closedToAllTime(value: marketInfo.atlPercentage)) } } - } extension MarketAdvancedSearchService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -333,11 +332,9 @@ extension MarketAdvancedSearchService { priceCloseToAtl = false priceCloseToAth = false } - } extension MarketAdvancedSearchService { - enum State { case loading case loaded(marketInfos: [MarketInfo]) @@ -420,7 +417,6 @@ extension MarketAdvancedSearchService { case .none, .moreB5, .moreB10, .moreB50, .moreB500: return Decimal.greatestFiniteMagnitude } } - } enum PriceChangeFilter: CaseIterable { @@ -461,7 +457,5 @@ extension MarketAdvancedSearchService { case .minus75: return -75 } } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewController.swift index 0b7d0f2120..c33656791f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewController.swift @@ -1,10 +1,10 @@ -import UIKit +import ComponentKit +import HUD +import RxSwift import SectionsTableView import SnapKit import ThemeKit -import RxSwift -import HUD -import ComponentKit +import UIKit class MarketAdvancedSearchViewController: ThemeViewController { private let viewModel: MarketAdvancedSearchViewModel @@ -36,11 +36,11 @@ class MarketAdvancedSearchViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func viewDidLoad() { super.viewDidLoad() @@ -130,36 +130,37 @@ class MarketAdvancedSearchViewController: ThemeViewController { private func buildSelector(cell: BaseThemeCell, title: String? = nil, viewItem: MarketAdvancedSearchViewModel.ViewItem? = nil) { let elements = tableView.universalImage24Elements( - title: .body(title), - value: viewItem.map { .subhead1($0.value, color: $0.valueStyle.valueTextColor )}, - accessoryType: .dropdown) - CellBuilderNew.buildStatic(cell: cell, rootElement: .hStack(elements) + title: .body(title), + value: viewItem.map { .subhead1($0.value, color: $0.valueStyle.valueTextColor) }, + accessoryType: .dropdown ) + CellBuilderNew.buildStatic(cell: cell, rootElement: .hStack(elements)) } - private func buildToggle(cell: BaseThemeCell, title: String? = nil, onToggle: @escaping (Bool) -> ()) { + private func buildToggle(cell: BaseThemeCell, title: String? = nil, onToggle: @escaping (Bool) -> Void) { let elements = tableView.universalImage24Elements( - title: .body(title), - accessoryType: .switch(onSwitch: onToggle)) + title: .body(title), + accessoryType: .switch(onSwitch: onToggle) + ) CellBuilderNew.buildStatic(cell: cell, rootElement: .hStack(elements)) } private func selectorItems(viewItems: [MarketAdvancedSearchViewModel.FilterViewItem]) -> [SelectorModule.ViewItem] { viewItems.map { SelectorModule.ViewItem( - title: $0.title, - titleColor: $0.style.filterTextColor, - selected: $0.selected + title: $0.title, + titleColor: $0.style.filterTextColor, + selected: $0.selected ) } } - private func showSelector(image: BottomSheetTitleView.Image, title: String, viewItems: [SelectorModule.ViewItem], onSelect: @escaping (Int) -> ()) { + private func showSelector(image: BottomSheetTitleView.Image, title: String, viewItems: [SelectorModule.ViewItem], onSelect: @escaping (Int) -> Void) { let viewController = SelectorModule.bottomSingleSelectorViewController( - image: image, - title: title, - viewItems: viewItems, - onSelect: onSelect + image: image, + title: title, + viewItems: viewItems, + onSelect: onSelect ) DispatchQueue.main.async { @@ -169,9 +170,9 @@ class MarketAdvancedSearchViewController: ThemeViewController { private func onTapCoinListCell() { showSelector( - image: .local(name: "circle_coin_24", tint: .warning), - title: "market.advanced_search.choose_set".localized, - viewItems: selectorItems(viewItems: viewModel.coinListViewItems) + image: .local(name: "circle_coin_24", tint: .warning), + title: "market.advanced_search.choose_set".localized, + viewItems: selectorItems(viewItems: viewModel.coinListViewItems) ) { [weak self] index in self?.viewModel.setCoinList(at: index) } @@ -179,9 +180,9 @@ class MarketAdvancedSearchViewController: ThemeViewController { private func onTapMarketCapCell() { showSelector( - image: .local(name: "usd_24", tint: .warning), - title: "market.advanced_search.market_cap".localized, - viewItems: selectorItems(viewItems: viewModel.marketCapViewItems) + image: .local(name: "usd_24", tint: .warning), + title: "market.advanced_search.market_cap".localized, + viewItems: selectorItems(viewItems: viewModel.marketCapViewItems) ) { [weak self] index in self?.viewModel.setMarketCap(at: index) } @@ -189,9 +190,9 @@ class MarketAdvancedSearchViewController: ThemeViewController { private func onTapVolumeCell() { showSelector( - image: .local(name: "chart_2_24", tint: .warning), - title: "market.advanced_search.volume".localized, - viewItems: selectorItems(viewItems: viewModel.volumeViewItems) + image: .local(name: "chart_2_24", tint: .warning), + title: "market.advanced_search.volume".localized, + viewItems: selectorItems(viewItems: viewModel.volumeViewItems) ) { [weak self] index in self?.viewModel.setVolume(at: index) } @@ -199,11 +200,11 @@ class MarketAdvancedSearchViewController: ThemeViewController { private func onTapBlockchainsCell() { let viewController = SelectorModule.multiSelectorViewController( - title: "market.advanced_search.blockchains".localized, - viewItems: viewModel.blockchainViewItems, - onFinish: { [weak self] in - self?.viewModel.setBlockchains(indexes: $0) - } + title: "market.advanced_search.blockchains".localized, + viewItems: viewModel.blockchainViewItems, + onFinish: { [weak self] in + self?.viewModel.setBlockchains(indexes: $0) + } ) present(viewController, animated: true) @@ -211,9 +212,9 @@ class MarketAdvancedSearchViewController: ThemeViewController { private func onTapPeriodCell() { showSelector( - image: .local(name: "circle_clock_24", tint: .warning), - title: "market.advanced_search.price_period".localized, - viewItems: selectorItems(viewItems: viewModel.priceChangeTypeViewItems) + image: .local(name: "circle_clock_24", tint: .warning), + title: "market.advanced_search.price_period".localized, + viewItems: selectorItems(viewItems: viewModel.priceChangeTypeViewItems) ) { [weak self] index in self?.viewModel.setPriceChangeType(at: index) } @@ -221,9 +222,9 @@ class MarketAdvancedSearchViewController: ThemeViewController { private func onTapPriceChangeCell() { showSelector( - image: .local(name: "markets_24", tint: .warning), - title: "market.advanced_search.price_change".localized, - viewItems: selectorItems(viewItems: viewModel.priceChangeViewItems) + image: .local(name: "markets_24", tint: .warning), + title: "market.advanced_search.price_change".localized, + viewItems: selectorItems(viewItems: viewModel.priceChangeViewItems) ) { [weak self] index in self?.viewModel.setPriceChange(at: index) } @@ -258,7 +259,7 @@ class MarketAdvancedSearchViewController: ThemeViewController { navigationController?.pushViewController(viewController, animated: true) } - private func set(isOn: Bool, cell: BaseThemeCell) { + private func set(isOn _: Bool, cell _: BaseThemeCell) { // cell.bind(index: 1) { (component: SwitchComponent) in // component.switchView.isOn = isOn // } @@ -299,96 +300,96 @@ class MarketAdvancedSearchViewController: ThemeViewController { spinner.isHidden = true showResultButton.setTitle("market.advanced_search.empty_results".localized, for: .normal) showResultButton.isEnabled = false - case .showResults(let count): + case let .showResults(count): spinner.isHidden = true showResultButton.setTitle("\("market.advanced_search.show_results".localized): \(count)", for: .normal) showResultButton.isEnabled = true - case .error(let description): + case let .error(description): spinner.isHidden = true showResultButton.setTitle(description, for: .normal) showResultButton.isEnabled = false } } - private func row(cell: UITableViewCell, id: String, height: CGFloat = .heightCell48, action: (() -> ())? = nil) -> RowProtocol { + private func row(cell: UITableViewCell, id: String, height: CGFloat = .heightCell48, action: (() -> Void)? = nil) -> RowProtocol { StaticRow( - cell: cell, - id: id, - height: height, - autoDeselect: true, - action: action + cell: cell, + id: id, + height: height, + autoDeselect: true, + action: action ) } - } extension MarketAdvancedSearchViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() sections.append(Section( - id: "coin_list", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin24), - rows: [ - row(cell: coinListCell, id: "coin_list") { [weak self] in - self?.onTapCoinListCell() - } - ]) + id: "coin_list", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin24), + rows: [ + row(cell: coinListCell, id: "coin_list") { [weak self] in + self?.onTapCoinListCell() + }, + ] + ) ) sections.append(Section( - id: "market_filters", - headerState: tableView.sectionHeader(text: "market.advanced_search.market_parameters".localized.uppercased()), - footerState: .margin(height: .margin24), - rows: [ - row(cell: marketCapCell, id: "market_cap") { [weak self] in - self?.onTapMarketCapCell() - }, - row(cell: volumeCell, id: "volume") { [weak self] in - self?.onTapVolumeCell() - } - ]) + id: "market_filters", + headerState: tableView.sectionHeader(text: "market.advanced_search.market_parameters".localized.uppercased()), + footerState: .margin(height: .margin24), + rows: [ + row(cell: marketCapCell, id: "market_cap") { [weak self] in + self?.onTapMarketCapCell() + }, + row(cell: volumeCell, id: "volume") { [weak self] in + self?.onTapVolumeCell() + }, + ] + ) ) sections.append(Section( - id: "network_filters", - headerState: tableView.sectionHeader(text: "market.advanced_search.network_parameters".localized.uppercased()), - footerState: .margin(height: .margin24), - rows: [ - row(cell: blockchainsCell, id: "blockchains") { [weak self] in - self?.onTapBlockchainsCell() - } - ]) + id: "network_filters", + headerState: tableView.sectionHeader(text: "market.advanced_search.network_parameters".localized.uppercased()), + footerState: .margin(height: .margin24), + rows: [ + row(cell: blockchainsCell, id: "blockchains") { [weak self] in + self?.onTapBlockchainsCell() + }, + ] + ) ) sections.append(Section( - id: "price_filters", - headerState: tableView.sectionHeader(text: "market.advanced_search.price_parameters".localized.uppercased()), - footerState: .margin(height: .margin32), - rows: [ - row(cell: priceChangeCell, id: "price_change") { [weak self] in - self?.onTapPriceChangeCell() - }, - row(cell: periodCell, id: "price_period") { [weak self] in - self?.onTapPeriodCell() - }, - row(cell: outperformedBtcCell, id: "outperformed_btc", height: .heightCell56), - row(cell: outperformedEthCell, id: "outperformed_eth", height: .heightCell56), - row(cell: outperformedBnbCell, id: "outperformed_bnb", height: .heightCell56), - row(cell: priceCloseToAthCell, id: "price_close_to_ath", height: .heightCell56), - row(cell: priceCloseToAtlCell, id: "price_close_to_atl", height: .heightCell56), - ]) + id: "price_filters", + headerState: tableView.sectionHeader(text: "market.advanced_search.price_parameters".localized.uppercased()), + footerState: .margin(height: .margin32), + rows: [ + row(cell: priceChangeCell, id: "price_change") { [weak self] in + self?.onTapPriceChangeCell() + }, + row(cell: periodCell, id: "price_period") { [weak self] in + self?.onTapPeriodCell() + }, + row(cell: outperformedBtcCell, id: "outperformed_btc", height: .heightCell56), + row(cell: outperformedEthCell, id: "outperformed_eth", height: .heightCell56), + row(cell: outperformedBnbCell, id: "outperformed_bnb", height: .heightCell56), + row(cell: priceCloseToAthCell, id: "price_close_to_ath", height: .heightCell56), + row(cell: priceCloseToAtlCell, id: "price_close_to_atl", height: .heightCell56), + ] + ) ) return sections } - } extension MarketAdvancedSearchViewModel.ValueStyle { - var valueTextColor: UIColor { switch self { case .none: return .themeGray @@ -406,5 +407,4 @@ extension MarketAdvancedSearchViewModel.ValueStyle { case .normal: return .themeLeah } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewModel.swift index 9f93ef69a5..29370bc842 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearch/MarketAdvancedSearchViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift class MarketAdvancedSearchViewModel { private let disposeBag = DisposeBag() @@ -47,7 +47,7 @@ class MarketAdvancedSearchViewModel { switch state { case .loading: buttonStateRelay.accept(.loading) - case .loaded(let marketInfos): + case let .loaded(marketInfos): if marketInfos.isEmpty { buttonStateRelay.accept(.emptyResults) } else { @@ -58,19 +58,19 @@ class MarketAdvancedSearchViewModel { } } - private func sync(coinList: MarketAdvancedSearchService.CoinListCount) { + private func sync(coinList _: MarketAdvancedSearchService.CoinListCount) { coinListViewItemRelay.accept(ViewItem(value: service.coinListCount.title, valueStyle: .normal)) } - private func sync(marketCap: MarketAdvancedSearchService.ValueFilter) { + private func sync(marketCap _: MarketAdvancedSearchService.ValueFilter) { marketCapViewItemRelay.accept(ViewItem(value: service.marketCap.title, valueStyle: service.marketCap.valueStyle)) } - private func sync(volume: MarketAdvancedSearchService.ValueFilter) { + private func sync(volume _: MarketAdvancedSearchService.ValueFilter) { volumeViewItemRelay.accept(ViewItem(value: service.volume.title, valueStyle: service.volume.valueStyle)) } - private func sync(blockchains: [Blockchain]) { + private func sync(blockchains _: [Blockchain]) { let value: String let valueStyle: ValueStyle @@ -88,18 +88,16 @@ class MarketAdvancedSearchViewModel { blockchainsViewItemRelay.accept(ViewItem(value: value, valueStyle: valueStyle)) } - private func sync(priceChangeType: MarketModule.PriceChangeType) { + private func sync(priceChangeType _: MarketModule.PriceChangeType) { priceChangeTypeViewItemRelay.accept(ViewItem(value: service.priceChangeType.title, valueStyle: .normal)) } - private func sync(priceChange: MarketAdvancedSearchService.PriceChangeFilter) { + private func sync(priceChange _: MarketAdvancedSearchService.PriceChangeFilter) { priceChangeViewItemRelay.accept(ViewItem(value: service.priceChange.title, valueStyle: service.priceChange.valueStyle)) } - } extension MarketAdvancedSearchViewModel { - var buttonStateDriver: Driver { buttonStateRelay.asDriver() } @@ -149,9 +147,9 @@ extension MarketAdvancedSearchViewModel { var blockchainViewItems: [SelectorModule.ViewItem] { service.allBlockchains.map { blockchain in SelectorModule.ViewItem( - image: .url(blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), - title: blockchain.name, - selected: service.blockchains.contains(blockchain) + image: .url(blockchain.type.imageUrl, placeholder: "placeholder_rectangle_32"), + title: blockchain.name, + selected: service.blockchains.contains(blockchain) ) } } @@ -169,7 +167,7 @@ extension MarketAdvancedSearchViewModel { } var marketInfos: [MarketInfo] { - guard case .loaded(let marketInfos) = service.state else { + guard case let .loaded(marketInfos) = service.state else { return [] } @@ -227,11 +225,9 @@ extension MarketAdvancedSearchViewModel { func reset() { service.reset() } - } extension MarketAdvancedSearchViewModel { - struct FilterViewItem { let title: String let style: ValueStyle @@ -256,19 +252,15 @@ extension MarketAdvancedSearchViewModel { case showResults(count: Int) case error(String) } - } extension MarketAdvancedSearchService.CoinListCount { - var title: String { - "market.advanced_search.top".localized(self.rawValue) + "market.advanced_search.top".localized(rawValue) } - } extension MarketAdvancedSearchService.ValueFilter { - static let valuesByCurrencyCode: [String: [Self]] = [ "USD": [.none, .lessM5, .m5m20, .m20m100, .m100b1, .b1b5, .moreB5], "EUR": [.none, .lessM5, .m5m20, .m20m100, .m100b1, .b1b5, .moreB5], @@ -282,7 +274,7 @@ extension MarketAdvancedSearchService.ValueFilter { "HKD": [.none, .lessM50, .m50m200, .m200b1, .b1b10, .b10b50, .moreB50], "ILS": [.none, .lessM10, .m10m40, .m40m200, .m200b2, .b2b10, .moreB10], "RUB": [.none, .lessM500, .m500b2, .b2b10, .b10b100, .b100b500, .moreB500], - "SGD": [.none, .lessM5, .m5m20, .m20m100, .m100b1, .b1b5, .moreB5] + "SGD": [.none, .lessM5, .m5m20, .m20m100, .m100b1, .b1b5, .moreB5], ] var title: String { @@ -317,11 +309,9 @@ extension MarketAdvancedSearchService.ValueFilter { var valueStyle: MarketAdvancedSearchViewModel.ValueStyle { self == .none ? .none : .normal } - } extension MarketAdvancedSearchService.PriceChangeFilter { - var title: String { switch self { case .none: return "selector.any".localized @@ -343,5 +333,4 @@ extension MarketAdvancedSearchService.PriceChangeFilter { case .minus10, .minus25, .minus50, .minus75: return .negative } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultModule.swift index 84588fa30d..307febf3e2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultModule.swift @@ -1,8 +1,7 @@ -import UIKit import MarketKit +import UIKit struct MarketAdvancedSearchResultModule { - static func viewController(marketInfos: [MarketInfo], priceChangeType: MarketModule.PriceChangeType) -> UIViewController { let service = MarketAdvancedSearchResultService(marketInfos: marketInfos, currencyManager: App.shared.currencyManager, priceChangeType: priceChangeType) let watchlistToggleService = MarketWatchlistToggleService(coinUidService: service, favoritesManager: App.shared.favoritesManager) @@ -13,5 +12,4 @@ struct MarketAdvancedSearchResultModule { return MarketAdvancedSearchResultViewController(listViewModel: listViewModel, headerViewModel: headerViewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultService.swift index 53edf41b7e..e3dddeef3d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketAdvancedSearchResults/MarketAdvancedSearchResultService.swift @@ -1,8 +1,8 @@ import Combine -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift class MarketAdvancedSearchResultService: IMarketMultiSortHeaderService { typealias Item = MarketInfo @@ -30,34 +30,27 @@ class MarketAdvancedSearchResultService: IMarketMultiSortHeaderService { private func syncState(reorder: Bool = false) { state = .loaded(items: marketInfos.sorted(sortingField: sortingField, priceChangeType: priceChangeType), softUpdate: false, reorder: reorder) } - } extension MarketAdvancedSearchResultService: IMarketListService { - var statePublisher: AnyPublisher, Never> { $state } - func refresh() { - } - + func refresh() {} } extension MarketAdvancedSearchResultService: IMarketListCoinUidService { - func coinUid(index: Int) -> String? { - guard case .loaded(let marketInfos, _, _) = state, index < marketInfos.count else { + guard case let .loaded(marketInfos, _, _) = state, index < marketInfos.count else { return nil } return marketInfos[index].fullCoin.coin.uid } - } extension MarketAdvancedSearchResultService: IMarketListDecoratorService { - var initialMarketFieldIndex: Int { 0 } @@ -66,10 +59,9 @@ extension MarketAdvancedSearchResultService: IMarketListDecoratorService { currencyManager.baseCurrency } - func onUpdate(marketFieldIndex: Int) { - if case .loaded(let marketInfos, _, _) = state { + func onUpdate(marketFieldIndex _: Int) { + if case let .loaded(marketInfos, _, _) = state { state = .loaded(items: marketInfos, softUpdate: false, reorder: false) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryMarketCapFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryMarketCapFetcher.swift index b19fcfc2ff..cdb7fe7cc6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryMarketCapFetcher.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryMarketCapFetcher.swift @@ -1,6 +1,6 @@ +import Chart import Foundation import MarketKit -import Chart class MarketCategoryMarketCapFetcher { private let marketKit: MarketKit.Kit @@ -12,11 +12,9 @@ class MarketCategoryMarketCapFetcher { self.currencyManager = currencyManager self.category = category } - } extension MarketCategoryMarketCapFetcher: IMetricChartFetcher { - var valueType: MetricChartModule.ValueType { .compactCurrencyValue(currencyManager.baseCurrency) } @@ -34,5 +32,4 @@ extension MarketCategoryMarketCapFetcher: IMetricChartFetcher { return MetricChartModule.ItemData(items: items, type: .regular) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewModel.swift index 6934fa6edc..efd7bf43f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewModel.swift @@ -4,11 +4,9 @@ class MarketCategoryViewModel { init(service: MarketCategoryService) { self.service = service } - } extension MarketCategoryViewModel { - var title: String { service.category.name } @@ -20,5 +18,4 @@ extension MarketCategoryViewModel { var imageUrl: String { service.category.imageUrl } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Category/MarketDiscoveryCategoryService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Category/MarketDiscoveryCategoryService.swift index 12b6a4fd28..10c25b7122 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Category/MarketDiscoveryCategoryService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Category/MarketDiscoveryCategoryService.swift @@ -1,9 +1,9 @@ import Foundation -import RxSwift -import RxRelay -import MarketKit -import HsToolKit import HsExtensions +import HsToolKit +import MarketKit +import RxRelay +import RxSwift class MarketDiscoveryCategoryService: IMarketSingleSortHeaderService { private static let allowedTimePeriods: [HsTimePeriod] = [.day1, .week1, .month1] @@ -39,18 +39,18 @@ class MarketDiscoveryCategoryService: IMarketSingleSortHeaderService { private var sortedItems: [DiscoveryItem] { let items = categories - .sorted { category, category2 in - guard let diff = category.diff(timePeriod: timePeriod) else { - return false - } - guard let diff2 = category2.diff(timePeriod: timePeriod) else { - return true - } - return sortDirectionAscending ? diff < diff2 : diff > diff2 + .sorted { category, category2 in + guard let diff = category.diff(timePeriod: timePeriod) else { + return false } - .map { category in - DiscoveryItem.category(category: category) + guard let diff2 = category2.diff(timePeriod: timePeriod) else { + return true } + return sortDirectionAscending ? diff < diff2 : diff > diff2 + } + .map { category in + DiscoveryItem.category(category: category) + } return [.topCoins] + items } @@ -60,11 +60,11 @@ class MarketDiscoveryCategoryService: IMarketSingleSortHeaderService { self.currencyManager = currencyManager reachabilityManager.reachabilityObservable - .observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] _ in - self?.refresh() - }) - .disposed(by: reachabilityDisposeBag) + .observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] _ in + self?.refresh() + }) + .disposed(by: reachabilityDisposeBag) sync() } @@ -93,7 +93,6 @@ class MarketDiscoveryCategoryService: IMarketSingleSortHeaderService { } private func sync(error: Error) { - // Try to get fallback from storage if categories empty yet, or return last items guard categories.isEmpty else { state = .items(sortedItems) @@ -115,21 +114,17 @@ class MarketDiscoveryCategoryService: IMarketSingleSortHeaderService { default: () } } - } extension MarketDiscoveryCategoryService { - func refresh() { if state.isEmpty { sync() } } - } extension MarketDiscoveryCategoryService { - enum DiscoveryItem { case topCoins case category(category: CoinCategory) @@ -143,19 +138,16 @@ extension MarketDiscoveryCategoryService { var isEmpty: Bool { switch self { case .loading: return false - case .items(let items): return items.isEmpty + case let .items(items): return items.isEmpty default: return true } } - } - } extension MarketDiscoveryCategoryService: IMarketSingleSortHeaderDecorator { - var allFields: [String] { - Self.allowedTimePeriods.map { $0.title } + Self.allowedTimePeriods.map(\.title) } var currentFieldIndex: Int { @@ -169,5 +161,4 @@ extension MarketDiscoveryCategoryService: IMarketSingleSortHeaderDecorator { timePeriod = Self.allowedTimePeriods[index] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/FilterCard.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/FilterCard.swift index 6cf616ab34..f000888762 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/FilterCard.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/FilterCard.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class FilterCard: UICollectionViewCell { private static let titleFont: UIFont = .subhead1 @@ -48,7 +48,8 @@ class FilterCard: UICollectionViewCell { contentView.backgroundColor = .themeLawrence } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -88,5 +89,4 @@ class FilterCard: UICollectionViewCell { return CGSize(width: width, height: 94) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilter.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilter.swift index 4d580d9c7f..86e2e91373 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilter.swift @@ -1,32 +1,30 @@ enum MarketDiscoveryFilter: String, CaseIterable { case blockchains = "blockchain" case dexEs = "dexes" - case lending = "lending" + case lending case yieldAggregators = "yield_aggregators" - case gaming = "gaming" - case oracles = "oracles" - case nft = "nft" - case privacy = "privacy" - case storage = "storage" - case wallets = "wallets" - case identity = "identity" - case scaling = "scaling" - case analytics = "analytics" + case gaming + case oracles + case nft + case privacy + case storage + case wallets + case identity + case scaling + case analytics case yieldTokens = "yield_tokens" case exchangeTokens = "exchange_tokens" case fiatStableCoins = "stablecoins" case tokenizedBitcoin = "tokenized_bitcoin" case riskManagement = "risk_management" - case synthetics = "synthetics" + case synthetics case indexFunds = "index_funds" case predictionMarkets = "prediction_markets" - case fundraising = "fundraising" - case infrastructure = "infrastructure" - + case fundraising + case infrastructure } extension MarketDiscoveryFilter { - var icon: String { switch self { case .blockchains: return "blocks_24" @@ -52,7 +50,6 @@ extension MarketDiscoveryFilter { case .storage: return "storage_24" case .identity: return "identity_24" case .yieldTokens: return "yield_24" - } } @@ -63,5 +60,4 @@ extension MarketDiscoveryFilter { var description: String { "market_discovery.filter_description.\(rawValue)".localized } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilterHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilterHeaderView.swift index 4a3317f2d5..e7cebafbcf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilterHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/Filter/MarketDiscoveryFilterHeaderView.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit extension MarketDiscoveryFilterHeaderView { struct ViewItem { @@ -18,7 +18,7 @@ class MarketDiscoveryFilterHeaderView: UIView { private let collectionView: UICollectionView private var loaded = false - var onSelect: ((Int?) -> ())? + var onSelect: ((Int?) -> Void)? init() { let layout = UICollectionViewFlowLayout() @@ -54,14 +54,13 @@ class MarketDiscoveryFilterHeaderView: UIView { loaded = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } - } extension MarketDiscoveryFilterHeaderView { - func set(filters: [MarketDiscoveryFilterHeaderView.ViewItem]) { self.filters = filters @@ -69,12 +68,10 @@ extension MarketDiscoveryFilterHeaderView { collectionView.reloadData() } } - } extension MarketDiscoveryFilterHeaderView: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { filters.count } @@ -82,17 +79,17 @@ extension MarketDiscoveryFilterHeaderView: UICollectionViewDelegateFlowLayout, U collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: FilterCard.self), for: indexPath) } - func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? FilterCard { cell.bind(item: filters[indexPath.item]) } } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { FilterCard.size(item: filters[indexPath.item]) } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { .margin12 } @@ -130,11 +127,9 @@ extension MarketDiscoveryFilterHeaderView: UICollectionViewDelegateFlowLayout, U private func handleSelect() { onSelect?(collectionView.indexPathsForSelectedItems?.first?.item) } - } extension MarketDiscoveryFilterHeaderView { - func setSelected(index: Int?) { guard collectionView.indexPathsForSelectedItems?.first?.item != index else { return @@ -144,5 +139,4 @@ extension MarketDiscoveryFilterHeaderView { collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally) collectionView.performBatchUpdates(nil) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryCell.swift index c34cae589d..c1623d0c28 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryCell.swift @@ -47,7 +47,8 @@ class MarketDiscoveryCell: UICollectionViewCell { nameLabel.textColor = .themeLeah } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -78,5 +79,4 @@ class MarketDiscoveryCell: UICollectionViewCell { maker.bottom.equalTo(stackView.snp.top).offset(viewItem.marketCap == nil ? 0 : -CGFloat.margin8) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryFilterService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryFilterService.swift index ca09cc0b4c..6aa02933eb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryFilterService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryFilterService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class MarketDiscoveryFilterService { private let marketKit: MarketKit.Kit @@ -22,17 +22,15 @@ class MarketDiscoveryFilterService { } private func coinUid(index: Int) -> String? { - guard case .searchResults(let fullCoins) = state, index < fullCoins.count else { + guard case let .searchResults(fullCoins) = state, index < fullCoins.count else { return nil } return fullCoins[index].coin.uid } - } extension MarketDiscoveryFilterService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -46,7 +44,7 @@ extension MarketDiscoveryFilterService { state = .idle } else { do { - state = .searchResults(fullCoins: try marketKit.fullCoins(filter: filter)) + state = try .searchResults(fullCoins: marketKit.fullCoins(filter: filter)) } catch { state = .searchResults(fullCoins: []) } @@ -80,11 +78,9 @@ extension MarketDiscoveryFilterService { favoritesManager.remove(coinUid: coinUid) resultRelay.accept(.unfavorited) } - } extension MarketDiscoveryFilterService { - enum State { case idle case searchResults(fullCoins: [FullCoin]) @@ -95,5 +91,4 @@ extension MarketDiscoveryFilterService { case unfavorited case fail } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryModule.swift index abc7d63a84..dce1e6d9b1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryModule.swift @@ -1,8 +1,7 @@ -import UIKit import MarketKit +import UIKit struct MarketDiscoveryModule { - static func viewController() -> UIViewController { let categoryService = MarketDiscoveryCategoryService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, reachabilityManager: App.shared.reachabilityManager) let filterService = MarketDiscoveryFilterService(marketKit: App.shared.marketKit, favoritesManager: App.shared.favoritesManager) @@ -40,5 +39,4 @@ struct MarketDiscoveryModule { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryTitleCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryTitleCell.swift index 0a13ac2658..f154bf0c73 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryTitleCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryTitleCell.swift @@ -26,8 +26,8 @@ class MarketDiscoveryTitleCell: UICollectionViewCell { topSeparatorView.backgroundColor = .themeSteel20 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewController.swift index e619b71086..53d783df81 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewController.swift @@ -126,7 +126,7 @@ class MarketDiscoveryViewController: ThemeSearchViewController { } private func sync(discoveryViewItems: [MarketDiscoveryViewModel.DiscoveryViewItem]?) { - if let discoveryViewItems = discoveryViewItems { + if let discoveryViewItems { self.discoveryViewItems = discoveryViewItems collectionView.reloadData() collectionView.isHidden = false @@ -138,7 +138,7 @@ class MarketDiscoveryViewController: ThemeSearchViewController { } private func sync(searchViewItems: [MarketDiscoveryViewModel.SearchViewItem]?) { - if let searchViewItems = searchViewItems { + if let searchViewItems { self.searchViewItems = searchViewItems reloadTable() tableView.isHidden = false diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewModel.swift index dd96219236..4c81b58059 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketDiscovery/MarketDiscoveryViewModel.swift @@ -1,9 +1,9 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import RxCocoa +import Foundation import MarketKit +import RxCocoa +import RxRelay +import RxSwift class MarketDiscoveryViewModel { private var queue = DispatchQueue(label: "\(AppConfig.label).market-discovery-view-model", qos: .userInitiated) @@ -17,17 +17,17 @@ class MarketDiscoveryViewModel { private let discoveryLoadingRelay = BehaviorRelay(value: false) private let discoveryErrorRelay = BehaviorRelay(value: nil) private let searchViewItemsRelay = BehaviorRelay<[SearchViewItem]?>(value: nil) - private let favoritedRelay = PublishRelay<()>() - private let unfavoritedRelay = PublishRelay<()>() - private let failRelay = PublishRelay<()>() + private let favoritedRelay = PublishRelay() + private let unfavoritedRelay = PublishRelay() + private let failRelay = PublishRelay() init(categoryService: MarketDiscoveryCategoryService, filterService: MarketDiscoveryFilterService) { self.categoryService = categoryService self.filterService = filterService categoryService.$state - .sink { [weak self] in self?.sync(categoryState: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(categoryState: $0) } + .store(in: &cancellables) subscribe(disposeBag, filterService.stateObservable) { [weak self] in self?.sync(filterState: $0) } subscribe(disposeBag, filterService.resultObservable) { [weak self] in self?.sync(result: $0) } @@ -56,7 +56,7 @@ class MarketDiscoveryViewModel { switch filterState { case .idle: searchViewItemsRelay.accept(nil) - case .searchResults(let fullCoins): + case let .searchResults(fullCoins): searchViewItemsRelay.accept(fullCoins.map { searchViewItem(fullCoin: $0) }) discoveryLoadingRelay.accept(false) discoveryErrorRelay.accept(nil) @@ -69,11 +69,11 @@ class MarketDiscoveryViewModel { discoveryErrorRelay.accept(nil) discoveryLoadingRelay.accept(true) discoveryViewItemsRelay.accept(nil) - case .items(let items): + case let .items(items): discoveryErrorRelay.accept(nil) discoveryLoadingRelay.accept(false) discoveryViewItemsRelay.accept(items.map { discoveryViewItem(item: $0) }) - case .failed(let error): + case let .failed(error): discoveryErrorRelay.accept(error.localizedDescription) discoveryLoadingRelay.accept(false) discoveryViewItemsRelay.accept(nil) @@ -84,42 +84,40 @@ class MarketDiscoveryViewModel { switch item { case .topCoins: return DiscoveryViewItem( - type: .topCoins, - imageUrl: "top_coins".headerImageUrl, - name: "market_discovery.top_coins".localized, - marketCap: nil, - diff: nil, - diffType: .up + type: .topCoins, + imageUrl: "top_coins".headerImageUrl, + name: "market_discovery.top_coins".localized, + marketCap: nil, + diff: nil, + diffType: .up ) - case .category(let category): + case let .category(category): let (marketCap, diffString, diffType) = MarketDiscoveryModule.formatCategoryMarketData(category: category, timePeriod: categoryService.timePeriod, currency: categoryService.currency) return DiscoveryViewItem( - type: .category(category: category), - imageUrl: category.imageUrl, - name: category.name, - marketCap: marketCap, - diff: diffString, - diffType: diffType + type: .category(category: category), + imageUrl: category.imageUrl, + name: category.name, + marketCap: marketCap, + diff: diffString, + diffType: diffType ) } } private func searchViewItem(fullCoin: FullCoin) -> SearchViewItem { SearchViewItem( - uid: fullCoin.coin.uid, - imageUrl: fullCoin.coin.imageUrl, - placeholderImageName: "placeholder_circle_32", - name: fullCoin.coin.name, - code: fullCoin.coin.code, - favorite: false + uid: fullCoin.coin.uid, + imageUrl: fullCoin.coin.imageUrl, + placeholderImageName: "placeholder_circle_32", + name: fullCoin.coin.name, + code: fullCoin.coin.code, + favorite: false ) } - } extension MarketDiscoveryViewModel { - var discoveryViewItemsDriver: Driver<[DiscoveryViewItem]?> { discoveryViewItemsRelay.asDriver() } @@ -136,15 +134,15 @@ extension MarketDiscoveryViewModel { searchViewItemsRelay.asDriver() } - var favoritedDriver: Driver<()> { + var favoritedDriver: Driver { favoritedRelay.asDriver(onErrorJustReturn: ()) } - var unfavoritedDriver: Driver<()> { + var unfavoritedDriver: Driver { unfavoritedRelay.asDriver(onErrorJustReturn: ()) } - var failDriver: Driver<()> { + var failDriver: Driver { failRelay.asDriver(onErrorJustReturn: ()) } @@ -167,11 +165,9 @@ extension MarketDiscoveryViewModel { func unfavorite(index: Int) { filterService.unfavorite(index: index) } - } extension MarketDiscoveryViewModel { - struct DiscoveryViewItem { let type: Type let imageUrl: String @@ -194,5 +190,4 @@ extension MarketDiscoveryViewModel { let code: String let favorite: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalFetcher.swift index 7f9c519367..96d5fb1ee8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalFetcher.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalFetcher.swift @@ -1,6 +1,6 @@ +import Chart import Foundation import MarketKit -import Chart class MarketGlobalFetcher { private let marketKit: MarketKit.Kit @@ -12,11 +12,9 @@ class MarketGlobalFetcher { self.currencyManager = currencyManager self.metricsType = metricsType } - } extension MarketGlobalFetcher: IMetricChartFetcher { - var valueType: MetricChartModule.ValueType { .compactCurrencyValue(currencyManager.baseCurrency) } @@ -28,7 +26,6 @@ extension MarketGlobalFetcher: IMetricChartFetcher { let items = points.map { point -> MetricChartModule.Item in let value: Decimal - switch metricsType { case .defiCap: value = point.defiMarketCap case .totalMarketCap: @@ -43,5 +40,4 @@ extension MarketGlobalFetcher: IMetricChartFetcher { let indicators = [MarketGlobalModule.dominance: dominancePoints] return MetricChartModule.ItemData(items: items, indicators: indicators, type: .regular) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalModule.swift index da303f84b7..95ed612df9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalModule.swift @@ -1,6 +1,6 @@ -import UIKit -import RxSwift import Chart +import RxSwift +import UIKit struct MarketGlobalModule { static let dominance = "dominance" @@ -43,7 +43,5 @@ struct MarketGlobalModule { case .tvlInDefi: return .price } } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketListDefiDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketListDefiDecorator.swift index 0169c856f6..20ae6175ba 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketListDefiDecorator.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketListDefiDecorator.swift @@ -15,13 +15,11 @@ class MarketListDefiDecorator { self.service = service marketField = MarketModule.MarketField.allCases[service.initialMarketFieldIndex] } - } extension MarketListDefiDecorator: IMarketSingleSortHeaderDecorator { - var allFields: [String] { - MarketModule.MarketField.allCases.map { $0.title } + MarketModule.MarketField.allCases.map(\.title) } var currentFieldIndex: Int { @@ -31,11 +29,9 @@ extension MarketListDefiDecorator: IMarketSingleSortHeaderDecorator { func setCurrentField(index: Int) { marketField = MarketModule.MarketField.allCases[index] } - } extension MarketListDefiDecorator: IMarketListDecorator { - func listViewItem(item: MarketGlobalDefiMetricService.DefiItem) -> MarketModule.ListViewItem { let marketInfo = item.marketInfo let currency = service.currency @@ -51,17 +47,16 @@ extension MarketListDefiDecorator: IMarketListDecorator { } return MarketModule.ListViewItem( - uid: marketInfo.fullCoin.coin.uid, - iconUrl: marketInfo.fullCoin.coin.imageUrl, - iconShape: .square, - iconPlaceholderName: "placeholder_circle_32", - leftPrimaryValue: marketInfo.fullCoin.coin.code, - leftSecondaryValue: marketInfo.fullCoin.coin.name, - badge: "\(item.tvlRank)", - badgeSecondaryValue: nil, - rightPrimaryValue: price, - rightSecondaryValue: dataValue + uid: marketInfo.fullCoin.coin.uid, + iconUrl: marketInfo.fullCoin.coin.imageUrl, + iconShape: .square, + iconPlaceholderName: "placeholder_circle_32", + leftPrimaryValue: marketInfo.fullCoin.coin.code, + leftSecondaryValue: marketInfo.fullCoin.coin.name, + badge: "\(item.tvlRank)", + badgeSecondaryValue: nil, + rightPrimaryValue: price, + rightSecondaryValue: dataValue ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlFetcher.swift index 778a0252d4..5ad8ea7029 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlFetcher.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlFetcher.swift @@ -1,7 +1,7 @@ -import Foundation +import Chart import Combine +import Foundation import MarketKit -import Chart class MarketGlobalTvlFetcher { private let marketKit: MarketKit.Kit @@ -15,11 +15,9 @@ class MarketGlobalTvlFetcher { self.currencyManager = currencyManager service = marketGlobalTvlPlatformService } - } extension MarketGlobalTvlFetcher: IMetricChartFetcher { - var valueType: MetricChartModule.ValueType { .compactCurrencyValue(currencyManager.baseCurrency) } @@ -37,5 +35,4 @@ extension MarketGlobalTvlFetcher: IMetricChartFetcher { return MetricChartModule.ItemData(items: items, type: .regular) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricService.swift index 5171e9c4ba..e2c3609206 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricService.swift @@ -110,7 +110,7 @@ class MarketGlobalTvlMetricService { private func subscribeChart() { cancellables = Set() - guard let chartService = chartService else { + guard let chartService else { return } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketListTvlDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketListTvlDecorator.swift index 96de1a6b08..67400bb78b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketListTvlDecorator.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketListTvlDecorator.swift @@ -9,11 +9,9 @@ class MarketListTvlDecorator { init(service: MarketGlobalTvlMetricService) { self.service = service } - } extension MarketListTvlDecorator: IMarketListDecorator { - func listViewItem(item defiCoin: DefiCoin) -> MarketModule.ListViewItem { let currency = service.currency @@ -23,12 +21,12 @@ extension MarketListTvlDecorator: IMarketListDecorator { let name: String switch defiCoin.type { - case .fullCoin(let fullCoin): + case let .fullCoin(fullCoin): uid = fullCoin.coin.uid iconUrl = fullCoin.coin.imageUrl iconPlaceholderName = "placeholder_circle_32" name = fullCoin.coin.name - case .defiCoin(let defiName, let logo): + case let .defiCoin(defiName, logo): iconUrl = logo iconPlaceholderName = "placeholder_circle_32" name = defiName @@ -63,17 +61,16 @@ extension MarketListTvlDecorator: IMarketListDecorator { } return MarketModule.ListViewItem( - uid: uid, - iconUrl: iconUrl, - iconShape: .square, - iconPlaceholderName: iconPlaceholderName, - leftPrimaryValue: name, - leftSecondaryValue: defiCoin.chains.count == 1 ? defiCoin.chains[0] : "market.global.tvl_in_defi.multi_chain".localized, - badge: "\(defiCoin.tvlRank)", - badgeSecondaryValue: nil, - rightPrimaryValue: tvl.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized, - rightSecondaryValue: diff + uid: uid, + iconUrl: iconUrl, + iconShape: .square, + iconPlaceholderName: iconPlaceholderName, + leftPrimaryValue: name, + leftSecondaryValue: defiCoin.chains.count == 1 ? defiCoin.chains[0] : "market.global.tvl_in_defi.multi_chain".localized, + badge: "\(defiCoin.tvlRank)", + badgeSecondaryValue: nil, + rightPrimaryValue: tvl.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized, + rightSecondaryValue: diff ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketHeaderCell.swift index 04f365c85c..83d17f4e54 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketHeaderCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketHeaderCell.swift @@ -40,7 +40,8 @@ class MarketHeaderCell: UITableViewCell { } } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -49,20 +50,17 @@ class MarketHeaderCell: UITableViewCell { descriptionLabel.text = description switch imageMode { - case .local(let image): + case let .local(image): rightImageView.image = image - case .remote(let imageUrl): + case let .remote(imageUrl): rightImageView.setImage(withUrlString: imageUrl, placeholder: nil) } } - } extension MarketHeaderCell { - enum ImageMode { case local(image: UIImage?) case remote(imageUrl: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListMarketFieldDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListMarketFieldDecorator.swift index ee01428cb5..53f278a8c5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListMarketFieldDecorator.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListMarketFieldDecorator.swift @@ -15,13 +15,11 @@ class MarketListMarketFieldDecorator { self.service = service marketField = MarketModule.MarketField.allCases[service.initialMarketFieldIndex] } - } extension MarketListMarketFieldDecorator: IMarketSingleSortHeaderDecorator { - var allFields: [String] { - MarketModule.MarketField.allCases.map { $0.title } + MarketModule.MarketField.allCases.map(\.title) } var currentFieldIndex: Int { @@ -31,11 +29,9 @@ extension MarketListMarketFieldDecorator: IMarketSingleSortHeaderDecorator { func setCurrentField(index: Int) { marketField = MarketModule.MarketField.allCases[index] } - } extension MarketListMarketFieldDecorator: IMarketListDecorator { - func listViewItem(item marketInfo: MarketInfo) -> MarketModule.ListViewItem { let currency = service.currency @@ -50,17 +46,16 @@ extension MarketListMarketFieldDecorator: IMarketListDecorator { } return MarketModule.ListViewItem( - uid: marketInfo.fullCoin.coin.uid, - iconUrl: marketInfo.fullCoin.coin.imageUrl, - iconShape: .full, - iconPlaceholderName: "placeholder_circle_32", - leftPrimaryValue: marketInfo.fullCoin.coin.code, - leftSecondaryValue: marketInfo.fullCoin.coin.name, - badge: marketInfo.marketCapRank.map { "\($0)" }, - badgeSecondaryValue: nil, - rightPrimaryValue: price, - rightSecondaryValue: dataValue + uid: marketInfo.fullCoin.coin.uid, + iconUrl: marketInfo.fullCoin.coin.imageUrl, + iconShape: .full, + iconPlaceholderName: "placeholder_circle_32", + leftPrimaryValue: marketInfo.fullCoin.coin.code, + leftSecondaryValue: marketInfo.fullCoin.coin.name, + badge: marketInfo.marketCapRank.map { "\($0)" }, + badgeSecondaryValue: nil, + rightPrimaryValue: price, + rightSecondaryValue: dataValue ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewController.swift index df4d45b753..2f72107b86 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewController.swift @@ -68,7 +68,7 @@ class MarketListViewController: ThemeViewController { tableView.sectionDataSource = self - if let emptyView = emptyView { + if let emptyView { view.addSubview(emptyView) emptyView.snp.makeConstraints { maker in maker.edges.equalTo(view.safeAreaLayoutGuide) @@ -126,19 +126,19 @@ class MarketListViewController: ThemeViewController { private func sync(viewItemData: MarketModule.ListViewItemData?) { viewItems = viewItemData?.viewItems - if let viewItems = viewItems, viewItems.isEmpty { + if let viewItems, viewItems.isEmpty { emptyView?.isHidden = false } else { emptyView?.isHidden = true } - if let viewItems = viewItems, !viewItems.isEmpty { + if let viewItems, !viewItems.isEmpty { tableView.bounces = true } else { tableView.bounces = false } - if let viewItemData = viewItemData { + if let viewItemData { tableView.reload(animated: viewItemData.softUpdate) } else { tableView.reload() @@ -206,7 +206,7 @@ extension MarketListViewController: SectionsDataSource { func buildSections() -> [SectionProtocol] { let headerState: ViewState - if let headerView = headerView, let viewItems = viewItems, !viewItems.isEmpty { + if let headerView, let viewItems, !viewItems.isEmpty { headerState = .static(view: headerView, height: .heightSingleLineCell) } else { headerState = .margin(height: 0) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewModel.swift index 586ca3741d..c2728525bb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewModel.swift @@ -1,9 +1,9 @@ import Combine -import RxSwift -import RxRelay -import RxCocoa -import MarketKit import HsExtensions +import MarketKit +import RxCocoa +import RxRelay +import RxSwift protocol IMarketListService { associatedtype Item @@ -45,7 +45,7 @@ class MarketListViewModel(value: nil) private let loadingRelay = BehaviorRelay(value: false) private let syncErrorRelay = BehaviorRelay(value: false) - private let scrollToTopRelay = PublishRelay<()>() + private let scrollToTopRelay = PublishRelay() init(service: Service, decorator: Decorator, itemLimit: Int? = nil) { self.service = service @@ -53,8 +53,8 @@ class MarketListViewModel { viewItemDataRelay.asDriver() } @@ -108,12 +106,11 @@ extension MarketListViewModel: IMarketListViewModel { syncErrorRelay.asDriver() } - var scrollToTopSignal: Signal<()> { + var scrollToTopSignal: Signal { scrollToTopRelay.asSignal() } func refresh() { service.refresh() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListWatchViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListWatchViewModel.swift index ec848d748c..3e9c80407e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListWatchViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListWatchViewModel.swift @@ -1,11 +1,11 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift protocol IMarketListWatchViewModel: IMarketListViewModel { - var favoriteDriver: Driver<()> { get } - var unfavoriteDriver: Driver<()> { get } + var favoriteDriver: Driver { get } + var unfavoriteDriver: Driver { get } var failDriver: Driver { get } func isFavorite(index: Int) -> Bool? @@ -18,8 +18,8 @@ class MarketListWatchViewModel() - private let unfavoriteRelay = PublishRelay<()>() + private let favoriteRelay = PublishRelay() + private let unfavoriteRelay = PublishRelay() private let failRelay = PublishRelay() init(service: Service, watchlistToggleService: MarketWatchlistToggleService, decorator: Decorator) { @@ -40,16 +40,14 @@ class MarketListWatchViewModel { + var favoriteDriver: Driver { favoriteRelay.asDriver(onErrorJustReturn: ()) } - var unfavoriteDriver: Driver<()> { + var unfavoriteDriver: Driver { unfavoriteRelay.asDriver(onErrorJustReturn: ()) } @@ -68,5 +66,4 @@ extension MarketListWatchViewModel: IMarketListWatchViewModel { func unfavorite(index: Int) { watchlistToggleService.unfavorite(index: index) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketWatchlistToggleService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketWatchlistToggleService.swift index fe9f9c795a..0822ece3d0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketWatchlistToggleService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketWatchlistToggleService.swift @@ -10,11 +10,9 @@ class MarketWatchlistToggleService { self.coinUidService = coinUidService self.favoritesManager = favoritesManager } - } extension MarketWatchlistToggleService { - var statusObservable: Observable { statusSubject.asObservable() } @@ -48,15 +46,12 @@ extension MarketWatchlistToggleService { statusSubject.onNext(.unfavorite) } - } extension MarketWatchlistToggleService { - enum State { case favorite case unfavorite case fail } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketModule.swift index ee009052d4..03f6d1fce2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketModule.swift @@ -112,7 +112,7 @@ enum MarketModule { case let .valueDiff(currencyValue, diff): title = nil - if let currencyValue = currencyValue, let diff = diff { + if let currencyValue, let diff { let valueDiff = diff * currencyValue.value / 100 value = ValueFormatter.instance.formatShort(currency: currencyValue.currency, value: valueDiff, showSign: true) ?? "----" color = valueDiff.isSignMinus ? .themeLucian : .themeRemus @@ -123,7 +123,7 @@ enum MarketModule { case let .diff(diff): title = nil value = diff.flatMap { ValueFormatter.instance.format(percentValue: $0) } ?? "----" - if let diff = diff { + if let diff { color = diff.isSignMinus ? .themeLucian : .themeRemus } else { color = .themeGray50 @@ -299,7 +299,7 @@ extension MarketKit.MarketInfo { } } -extension Array where Element == MarketKit.MarketInfo { +extension [MarketKit.MarketInfo] { func sorted(sortingField: MarketModule.SortingField, priceChangeType: MarketModule.PriceChangeType) -> [MarketKit.MarketInfo] { sorted { lhsMarketInfo, rhsMarketInfo in switch sortingField { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketListNftCollectionDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketListNftCollectionDecorator.swift index 7ae226e79d..a1f401883c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketListNftCollectionDecorator.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketListNftCollectionDecorator.swift @@ -13,11 +13,9 @@ class MarketListNftCollectionDecorator { init(service: IMarketListNftTopCollectionDecoratorService) { self.service = service } - } extension MarketListNftCollectionDecorator: IMarketListDecorator { - func listViewItem(item: NftCollectionItem) -> MarketModule.ListViewItem { let collection = item.collection @@ -30,28 +28,26 @@ extension MarketListNftCollectionDecorator: IMarketListDecorator { } } - var volumeString = "n/a".localized let volume = collection.volumes[service.timePeriod] let diff = collection.changes[service.timePeriod] - if let volume = volume, let value = ValueFormatter.instance.formatShort(coinValue: CoinValue(kind: .token(token: volume.token), value: volume.value)) { + if let volume, let value = ValueFormatter.instance.formatShort(coinValue: CoinValue(kind: .token(token: volume.token), value: volume.value)) { volumeString = value } let dataValue: MarketModule.MarketDataValue = .diff(diff) return MarketModule.ListViewItem( - uid: collection.uid, - iconUrl: collection.thumbnailImageUrl ?? "", - iconShape: .square, - iconPlaceholderName: "placeholder_rectangle_32", - leftPrimaryValue: collection.name, - leftSecondaryValue: floorPriceString, - badge: "\(item.index)", - badgeSecondaryValue: nil, - rightPrimaryValue: volumeString, - rightSecondaryValue: dataValue + uid: collection.uid, + iconUrl: collection.thumbnailImageUrl ?? "", + iconShape: .square, + iconPlaceholderName: "placeholder_rectangle_32", + leftPrimaryValue: collection.name, + leftSecondaryValue: floorPriceString, + badge: "\(item.index)", + badgeSecondaryValue: nil, + rightPrimaryValue: volumeString, + rightSecondaryValue: dataValue ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsModule.swift index 1019c7902d..811caf5ce9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsModule.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit struct MarketNftTopCollectionsModule { - static func viewController(timePeriod: HsTimePeriod) -> UIViewController { let service = MarketNftTopCollectionsService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, timePeriod: timePeriod) @@ -38,19 +37,15 @@ struct MarketNftTopCollectionsModule { HsTimePeriod.week1, HsTimePeriod.month1] } - } extension NftTopCollection { - var uid: String { "\(blockchainType.uid)-\(providerUid)" } - } -extension Array where Element == NftTopCollection { - +extension [NftTopCollection] { func sorted(sortType: MarketNftTopCollectionsModule.SortType, timePeriod: HsTimePeriod) -> [NftTopCollection] { sorted { lhsCollection, rhsCollection in let lhsVolume = lhsCollection.volumes[timePeriod]?.value @@ -61,19 +56,19 @@ extension Array where Element == NftTopCollection { switch sortType { case .highestVolume, .lowestVolume: - guard let lhsVolume = lhsVolume else { + guard let lhsVolume else { return true } - guard let rhsVolume = rhsVolume else { + guard let rhsVolume else { return false } return sortType == .highestVolume ? lhsVolume > rhsVolume : lhsVolume < rhsVolume case .topGainers, .topLosers: - guard let lhsChange = lhsChange else { + guard let lhsChange else { return true } - guard let rhsChange = rhsChange else { + guard let rhsChange else { return false } @@ -81,5 +76,4 @@ extension Array where Element == NftTopCollection { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsService.swift index 19b54fcac8..9c886791ff 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsService.swift @@ -1,8 +1,8 @@ import Combine -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift struct NftCollectionItem { let index: Int @@ -58,23 +58,21 @@ class MarketNftTopCollectionsService { } private func syncIfPossible() { - guard case .loaded(let collections, _, _) = internalState else { + guard case let .loaded(collections, _, _) = internalState else { return } sync(collections: collections, reorder: true) } - } extension MarketNftTopCollectionsService: IMarketListService { - var statePublisher: AnyPublisher, Never> { $state } func topCollection(uid: String) -> NftTopCollection? { - guard case .loaded(let collections, _, _) = internalState else { + guard case let .loaded(collections, _, _) = internalState else { return nil } @@ -84,8 +82,6 @@ extension MarketNftTopCollectionsService: IMarketListService { func refresh() { sync() } - } -extension MarketNftTopCollectionsService: IMarketListNftTopCollectionDecoratorService { -} +extension MarketNftTopCollectionsService: IMarketListNftTopCollectionDecoratorService {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewModel.swift index d9a0e49e5f..a4c47bf378 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewModel.swift @@ -10,5 +10,4 @@ class MarketNftTopCollectionsViewModel { func topCollection(uid: String) -> NftTopCollection? { service.topCollection(uid: uid) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/NftCollectionsMultiSortHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/NftCollectionsMultiSortHeaderViewModel.swift index 45c292d263..54f71c9e6a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/NftCollectionsMultiSortHeaderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/NftCollectionsMultiSortHeaderViewModel.swift @@ -8,14 +8,13 @@ class NftCollectionsMultiSortHeaderViewModel { self.service = service self.decorator = decorator } - } extension NftCollectionsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel { - var sortItems: [String] { - MarketNftTopCollectionsModule.SortType.allCases.map { $0.title } + MarketNftTopCollectionsModule.SortType.allCases.map(\.title) } + var sortIndex: Int { MarketNftTopCollectionsModule.SortType.allCases.firstIndex(of: service.sortType) ?? 0 } @@ -23,12 +22,13 @@ extension NftCollectionsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewMode var leftSelectorItems: [String] { [] } + var leftSelectorIndex: Int { 0 } var rightSelectorItems: [String] { - MarketNftTopCollectionsModule.selectorValues.map { $0.title } + MarketNftTopCollectionsModule.selectorValues.map(\.title) } var rightSelectorIndex: Int { @@ -39,11 +39,9 @@ extension NftCollectionsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewMode service.sortType = MarketNftTopCollectionsModule.SortType.allCases[index] } - func onSelectLeft(index: Int) { - } + func onSelectLeft(index _: Int) {} func onSelectRight(index: Int) { service.timePeriod = MarketNftTopCollectionsModule.selectorValues[index] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/BaseMarketOverviewTopListDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/BaseMarketOverviewTopListDataSource.swift index 658050d746..176df3590a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/BaseMarketOverviewTopListDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/BaseMarketOverviewTopListDataSource.swift @@ -1,9 +1,9 @@ -import UIKit -import RxSwift -import RxCocoa -import SectionsTableView import Chart import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import UIKit protocol IBaseMarketOverviewTopListViewModel { var listViewItemsDriver: Driver<[MarketModule.ListViewItem]?> { get } @@ -37,44 +37,41 @@ class BaseMarketOverviewTopListDataSource { private func rows(tableView: SectionsTableView, listViewItems: [MarketModule.ListViewItem]) -> [RowProtocol] { listViewItems.enumerated().map { index, listViewItem in MarketModule.marketListCell( - tableView: tableView, - backgroundStyle: .lawrence, - listViewItem: listViewItem, - isFirst: index == 0, - isLast: false, - rowActionProvider: nil, - action: { [weak self] in - self?.onSelect(listViewItem: listViewItem) - }) + tableView: tableView, + backgroundStyle: .lawrence, + listViewItem: listViewItem, + isFirst: index == 0, + isLast: false, + rowActionProvider: nil, + action: { [weak self] in + self?.onSelect(listViewItem: listViewItem) + } + ) } } - private func seeAllRow(tableView: SectionsTableView, id: String, action: @escaping () -> ()) -> RowProtocol { + private func seeAllRow(tableView: SectionsTableView, id: String, action: @escaping () -> Void) -> RowProtocol { tableView.universalRow48( - id: id, - title: .body("market.top.section.header.see_all".localized), - accessoryType: .disclosure, - autoDeselect: true, - isLast: true, - action: action + id: id, + title: .body("market.top.section.header.see_all".localized), + accessoryType: .disclosure, + autoDeselect: true, + isLast: true, + action: action ) } - func didTapSeeAll() { - } - - func onSelect(listViewItem: MarketModule.ListViewItem) { - } + func didTapSeeAll() {} + func onSelect(listViewItem _: MarketModule.ListViewItem) {} } extension BaseMarketOverviewTopListDataSource: IMarketOverviewDataSource { - var isReady: Bool { listViewItemsRelay.value != nil } - var updateObservable: Observable<()> { + var updateObservable: Observable { listViewItemsRelay.map { _ in () } } @@ -101,31 +98,31 @@ extension BaseMarketOverviewTopListDataSource: IMarketOverviewDataSource { var sections = [SectionProtocol]() let headerSection = Section( - id: "header_\(title)", - footerState: .margin(height: .margin8), - rows: [ - Row( - id: "header_\(title)", - height: .heightCell48, - bind: { [weak self] cell, _ in - self?.bind(cell: cell) - } - ) - ] + id: "header_\(title)", + footerState: .margin(height: .margin8), + rows: [ + Row( + id: "header_\(title)", + height: .heightCell48, + bind: { [weak self] cell, _ in + self?.bind(cell: cell) + } + ), + ] ) let listSection = Section( - id: title, - footerState: .margin(height: .margin24), - rows: rows(tableView: tableView, listViewItems: listViewItems) + [ - seeAllRow( - tableView: tableView, - id: "\(title)-see-all", - action: { [weak self] in - self?.didTapSeeAll() - } - ) - ] + id: title, + footerState: .margin(height: .margin24), + rows: rows(tableView: tableView, listViewItems: listViewItems) + [ + seeAllRow( + tableView: tableView, + id: "\(title)-see-all", + action: { [weak self] in + self?.didTapSeeAll() + } + ), + ] ) sections.append(headerSection) @@ -133,5 +130,4 @@ extension BaseMarketOverviewTopListDataSource: IMarketOverviewDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryCell.swift index 93a48052d3..5d57bce20b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryCell.swift @@ -1,11 +1,11 @@ -import UIKit -import SnapKit import MarketKit +import SnapKit +import UIKit class MarketOverviewCategoryCell: UITableViewCell { static let cellHeight: CGFloat = 316 - var onSelect: ((String) -> ())? + var onSelect: ((String) -> Void)? private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) @@ -32,58 +32,52 @@ class MarketOverviewCategoryCell: UITableViewCell { collectionView.register(MarketDiscoveryCell.self, forCellWithReuseIdentifier: String(describing: MarketDiscoveryCell.self)) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension MarketOverviewCategoryCell: UICollectionViewDataSource { - - func numberOfSections(in collectionView: UICollectionView) -> Int { + func numberOfSections(in _: UICollectionView) -> Int { 1 } - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { viewItems.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: MarketDiscoveryCell.self), for: indexPath) } - } extension MarketOverviewCategoryCell: UICollectionViewDelegate { - - func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? MarketDiscoveryCell { cell.set(viewItem: viewItems[indexPath.item]) } } - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, didSelectItemAt indexPath: IndexPath) { onSelect?(viewItems[indexPath.item].uid) } - } extension MarketOverviewCategoryCell: UICollectionViewDelegateFlowLayout { - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt _: IndexPath) -> CGSize { CGSize(width: (collectionView.width - .margin16 * 2 - .margin12) / 2, height: MarketDiscoveryCell.cellHeight) } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, insetForSectionAt _: Int) -> UIEdgeInsets { UIEdgeInsets(top: 0, left: .margin16, bottom: 0, right: .margin16) } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { .margin12 } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumLineSpacingForSectionAt _: Int) -> CGFloat { .margin12 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryService.swift index 65d99ab923..4ffe90fe79 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryService.swift @@ -1,8 +1,8 @@ -import Foundation import Combine -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class MarketOverviewCategoryService { private let baseService: MarketOverviewService @@ -19,8 +19,8 @@ class MarketOverviewCategoryService { self.baseService = baseService baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync() } @@ -32,11 +32,9 @@ class MarketOverviewCategoryService { item.marketOverview.coinCategories } } - } extension MarketOverviewCategoryService { - var categoriesObservable: Observable<[CoinCategory]?> { categoriesRelay.asObservable() } @@ -48,5 +46,4 @@ extension MarketOverviewCategoryService { func category(uid: String) -> CoinCategory? { categories?.first { $0.uid == uid } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryViewModel.swift index ef71ab7232..b86de7c450 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class MarketOverviewCategoryViewModel { private let service: MarketOverviewCategoryService @@ -25,19 +25,17 @@ class MarketOverviewCategoryViewModel { let (marketCap, diffString, diffType) = MarketDiscoveryModule.formatCategoryMarketData(category: category, timePeriod: .day1, currency: service.currency) return ViewItem( - uid: category.uid, - imageUrl: category.imageUrl, - name: category.name, - marketCap: marketCap, - diff: diffString, - diffType: diffType + uid: category.uid, + imageUrl: category.imageUrl, + name: category.name, + marketCap: marketCap, + diff: diffString, + diffType: diffType ) } - } extension MarketOverviewCategoryViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -45,11 +43,9 @@ extension MarketOverviewCategoryViewModel { func category(uid: String) -> CoinCategory? { service.category(uid: uid) } - } extension MarketOverviewCategoryViewModel { - struct ViewItem { let uid: String let imageUrl: String @@ -58,5 +54,4 @@ extension MarketOverviewCategoryViewModel { let diff: String? let diffType: MarketDiscoveryModule.DiffType } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalDataSource.swift index 13d32db18a..8116c07e43 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalDataSource.swift @@ -1,9 +1,9 @@ -import UIKit -import RxSwift -import RxCocoa -import SectionsTableView import Chart import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import UIKit class MarketOverviewGlobalDataSource { private let viewModel: MarketOverviewGlobalViewModel @@ -21,29 +21,27 @@ class MarketOverviewGlobalDataSource { marketMetricsCell = MarketOverviewMetricsCell(chartConfiguration: ChartConfiguration.smallPreviewChart, presentDelegate: presentDelegate) marketMetricsRow = StaticRow( - cell: marketMetricsCell, - id: "metrics", - height: MarketOverviewMetricsCell.cellHeight + cell: marketMetricsCell, + id: "metrics", + height: MarketOverviewMetricsCell.cellHeight ) subscribe(disposeBag, viewModel.viewItemDriver) { [weak self] viewItem in self?.viewItemRelay.accept(viewItem) } } - } extension MarketOverviewGlobalDataSource: IMarketOverviewDataSource { - var isReady: Bool { viewItemRelay.value != nil } - var updateObservable: Observable<()> { + var updateObservable: Observable { viewItemRelay.map { _ in () } } - func sections(tableView: SectionsTableView) -> [SectionProtocol] { + func sections(tableView _: SectionsTableView) -> [SectionProtocol] { guard let viewItem = viewItemRelay.value else { return [] } @@ -54,10 +52,9 @@ extension MarketOverviewGlobalDataSource: IMarketOverviewDataSource { return [ Section( - id: "market_metrics", - rows: [marketMetricsRow] - ) + id: "market_metrics", + rows: [marketMetricsRow] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalService.swift index 44bbd3590b..f2509689cb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalService.swift @@ -1,8 +1,8 @@ -import Foundation import Combine -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class MarketOverviewGlobalService { private let baseService: MarketOverviewService @@ -19,8 +19,8 @@ class MarketOverviewGlobalService { self.baseService = baseService baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync() } @@ -48,18 +48,18 @@ class MarketOverviewGlobalService { } return GlobalMarketData( - marketCap: globalMarketItem(pointItems: marketCapPointItems), - volume24h: globalMarketItem(pointItems: volume24hPointItems), - defiMarketCap: globalMarketItem(pointItems: defiMarketCapPointItems), - defiTvl: globalMarketItem(pointItems: tvlPointItems) + marketCap: globalMarketItem(pointItems: marketCapPointItems), + volume24h: globalMarketItem(pointItems: volume24hPointItems), + defiMarketCap: globalMarketItem(pointItems: defiMarketCapPointItems), + defiTvl: globalMarketItem(pointItems: tvlPointItems) ) } private func globalMarketItem(pointItems: [GlobalMarketPointItem]) -> GlobalMarketItem { GlobalMarketItem( - amount: amount(pointItems: pointItems), - diff: diff(pointItems: pointItems), - pointItems: pointItems + amount: amount(pointItems: pointItems), + diff: diff(pointItems: pointItems), + pointItems: pointItems ) } @@ -78,11 +78,9 @@ class MarketOverviewGlobalService { return (lastAmount - firstAmount) * 100 / firstAmount } - } extension MarketOverviewGlobalService { - var globalMarketDataObservable: Observable { globalMarketDataRelay.asObservable() } @@ -90,11 +88,9 @@ extension MarketOverviewGlobalService { var currency: Currency { baseService.currency } - } extension MarketOverviewGlobalService { - struct GlobalMarketData { let marketCap: GlobalMarketItem let volume24h: GlobalMarketItem @@ -112,5 +108,4 @@ extension MarketOverviewGlobalService { let timestamp: TimeInterval let amount: Decimal } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalViewModel.swift index c3b45c6f5e..12e93973ca 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalViewModel.swift @@ -1,9 +1,9 @@ +import Chart import Foundation -import RxSwift -import RxRelay -import RxCocoa import MarketKit -import Chart +import RxCocoa +import RxRelay +import RxSwift class MarketOverviewGlobalViewModel { private let service: MarketOverviewGlobalService @@ -25,10 +25,10 @@ class MarketOverviewGlobalViewModel { private func viewItem(globalMarketData: MarketOverviewGlobalService.GlobalMarketData) -> GlobalMarketViewItem { GlobalMarketViewItem( - totalMarketCap: chartViewItem(item: globalMarketData.marketCap), - volume24h: chartViewItem(item: globalMarketData.volume24h), - defiCap: chartViewItem(item: globalMarketData.defiMarketCap), - defiTvl: chartViewItem(item: globalMarketData.defiTvl) + totalMarketCap: chartViewItem(item: globalMarketData.marketCap), + volume24h: chartViewItem(item: globalMarketData.volume24h), + defiCap: chartViewItem(item: globalMarketData.defiMarketCap), + defiTvl: chartViewItem(item: globalMarketData.defiTvl) ) } @@ -54,32 +54,28 @@ class MarketOverviewGlobalViewModel { } chartData = ChartData( - items: chartItems, - startWindow: firstPointItem.timestamp, - endWindow: lastPointItem.timestamp + items: chartItems, + startWindow: firstPointItem.timestamp, + endWindow: lastPointItem.timestamp ) } return ChartViewItem( - value: value, - diff: item.diff, - chartData: chartData, - chartTrend: trend + value: value, + diff: item.diff, + chartData: chartData, + chartTrend: trend ) } - } extension MarketOverviewGlobalViewModel { - var viewItemDriver: Driver { viewItemRelay.asDriver() } - } extension MarketOverviewGlobalViewModel { - struct GlobalMarketViewItem { let totalMarketCap: ChartViewItem let volume24h: ChartViewItem @@ -93,5 +89,4 @@ extension MarketOverviewGlobalViewModel { let chartData: ChartData? let chartTrend: MovementTrend } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewHeaderCell.swift index 844fb1bb3b..b4f5c112ab 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewHeaderCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewHeaderCell.swift @@ -1,6 +1,6 @@ -import UIKit -import SnapKit import ComponentKit +import SnapKit +import UIKit class MarketOverviewHeaderCell: BaseThemeCell { private let leftImage = ImageComponent(size: .iconSize24) @@ -9,13 +9,14 @@ class MarketOverviewHeaderCell: BaseThemeCell { private let rightButton = SelectorButton() private let seeAllButton = SecondaryButton() - var onSelect: ((Int) -> ())? { + var onSelect: ((Int) -> Void)? { didSet { rightButton.onSelect = onSelect } } - var onSeeAll: (() -> ())? - var onTapTitle: (() -> ())? + + var onSeeAll: (() -> Void)? + var onTapTitle: (() -> Void)? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -70,7 +71,8 @@ class MarketOverviewHeaderCell: BaseThemeCell { seeAllButton.addTarget(self, action: #selector(onTapSeeAll), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -128,15 +130,12 @@ class MarketOverviewHeaderCell: BaseThemeCell { } } } - } extension MarketOverviewHeaderCell { - enum ButtonMode { case selector case seeAll case none } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewMetricsCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewMetricsCell.swift index 2d144adcd8..3c0657c009 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewMetricsCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewMetricsCell.swift @@ -1,9 +1,9 @@ -import UIKit -import SnapKit -import ThemeKit -import HUD import Chart import ComponentKit +import HUD +import SnapKit +import ThemeKit +import UIKit class MarketOverviewMetricsCell: UITableViewCell { static let cellHeight: CGFloat = 250 @@ -71,7 +71,8 @@ class MarketOverviewMetricsCell: UITableViewCell { deFiTvlView.title = "market.defi_tvl".localized } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -79,27 +80,22 @@ class MarketOverviewMetricsCell: UITableViewCell { let viewController = MarketGlobalMetricModule.viewController(type: metricType) presentDelegate?.present(viewController: viewController) } - } extension MarketOverviewMetricsCell { - func set(viewItem: MarketOverviewGlobalViewModel.GlobalMarketViewItem) { totalMarketCapView.set(viewItem: viewItem.totalMarketCap) volume24hView.set(viewItem: viewItem.volume24h) deFiCapView.set(viewItem: viewItem.defiCap) deFiTvlView.set(viewItem: viewItem.defiTvl) } - } extension MarketCardView { - func set(viewItem: MarketOverviewGlobalViewModel.ChartViewItem) { value = viewItem.value descriptionText = DiffLabel.formatted(value: viewItem.diff) descriptionColor = DiffLabel.color(value: viewItem.diff) set(chartData: viewItem.chartData, trend: viewItem.chartTrend) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewModule.swift index 39bdbeb0b7..22a7406df1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewModule.swift @@ -1,5 +1,4 @@ -struct MarketOverviewModule { - +enum MarketOverviewModule { static func viewController(presentDelegate: IPresentDelegate) -> MarketOverviewViewController { let service = MarketOverviewService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, appManager: App.shared.appManager) @@ -39,8 +38,7 @@ struct MarketOverviewModule { topLosersDataSource, categoryDataSource, nftCollectionsDataSource, - topPlatformsDataSource + topPlatformsDataSource, ]) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewController.swift index 63be128cac..2836fed6a4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewController.swift @@ -1,15 +1,15 @@ -import UIKit -import RxSwift -import RxCocoa -import ThemeKit -import SectionsTableView +import Chart import ComponentKit import HUD -import Chart +import RxCocoa +import RxSwift +import SectionsTableView +import ThemeKit +import UIKit protocol IMarketOverviewDataSource { var isReady: Bool { get } - var updateObservable: Observable<()> { get } + var updateObservable: Observable { get } func sections(tableView: SectionsTableView) -> [SectionProtocol] } @@ -31,7 +31,8 @@ class MarketOverviewViewController: ThemeViewController { super.init() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -109,19 +110,16 @@ class MarketOverviewViewController: ThemeViewController { } func handleDataSourceUpdate() { - guard dataSources.allSatisfy({ $0.isReady }) else { + guard dataSources.allSatisfy(\.isReady) else { return } tableView.reload() } - } extension MarketOverviewViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { dataSources.compactMap { $0.sections(tableView: tableView) }.flatMap { $0 } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewModel.swift index 50d0c747d0..641a19810c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewModel.swift @@ -1,7 +1,7 @@ import Combine -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class MarketOverviewViewModel { private let service: MarketOverviewService @@ -15,8 +15,8 @@ class MarketOverviewViewModel { self.service = service service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: service.state) } @@ -37,11 +37,9 @@ class MarketOverviewViewModel { successRelay.accept(false) } } - } extension MarketOverviewViewModel { - var successDriver: Driver { successRelay.asDriver() } @@ -61,5 +59,4 @@ extension MarketOverviewViewModel { func refresh() { service.refresh() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsService.swift index 3b8c2cdef1..7fb2261c63 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsService.swift @@ -1,8 +1,8 @@ -import Foundation import Combine -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class MarketOverviewTopCoinsService { private let baseService: MarketOverviewService @@ -23,8 +23,8 @@ class MarketOverviewTopCoinsService { self.baseService = baseService baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(state: baseService.state) } @@ -47,11 +47,9 @@ class MarketOverviewTopCoinsService { } } } - } extension MarketOverviewTopCoinsService { - var marketInfosObservable: Observable<[MarketInfo]?> { marketInfosRelay.asObservable() } @@ -60,11 +58,9 @@ extension MarketOverviewTopCoinsService { self.marketTop = marketTop sync(state: baseService.state) } - } extension MarketOverviewTopCoinsService: IMarketListDecoratorService { - var initialMarketFieldIndex: Int { 0 } @@ -77,13 +73,10 @@ extension MarketOverviewTopCoinsService: IMarketListDecoratorService { .day } - func onUpdate(marketFieldIndex: Int) { - } - + func onUpdate(marketFieldIndex _: Int) {} } extension MarketOverviewTopCoinsService { - enum ListType: String, CaseIterable { case topGainers case topLosers @@ -101,5 +94,4 @@ extension MarketOverviewTopCoinsService { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsViewModel.swift index a71b9753ff..3c9bf0146e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class MarketOverviewTopCoinsViewModel { private let service: MarketOverviewTopCoinsService @@ -22,11 +22,9 @@ class MarketOverviewTopCoinsViewModel { private func sync(marketInfos: [MarketInfo]?) { listViewItemsRelay.accept(marketInfos.map { $0.map { decorator.listViewItem(item: $0) } }) } - } extension MarketOverviewTopCoinsViewModel { - var marketTop: MarketModule.MarketTop { service.marketTop } @@ -34,17 +32,15 @@ extension MarketOverviewTopCoinsViewModel { var listType: MarketOverviewTopCoinsService.ListType { service.listType } - } extension MarketOverviewTopCoinsViewModel: IBaseMarketOverviewTopListViewModel { - var listViewItemsDriver: Driver<[MarketModule.ListViewItem]?> { listViewItemsRelay.asDriver() } var selectorTitles: [String] { - MarketModule.MarketTop.allCases.map { $0.title } + MarketModule.MarketTop.allCases.map(\.title) } var selectorIndex: Int { @@ -55,5 +51,4 @@ extension MarketOverviewTopCoinsViewModel: IBaseMarketOverviewTopListViewModel { let marketTop = MarketModule.MarketTop.allCases[selectorIndex] service.set(marketTop: marketTop) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsDataSource.swift index 91a5badec7..027d8661e7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsDataSource.swift @@ -1,5 +1,5 @@ -import UIKit import ThemeKit +import UIKit class MarketOverviewNftCollectionsDataSource: BaseMarketOverviewTopListDataSource { private let viewModel: MarketOverviewNftCollectionsViewModel @@ -8,11 +8,11 @@ class MarketOverviewNftCollectionsDataSource: BaseMarketOverviewTopListDataSourc self.viewModel = viewModel super.init( - topListViewModel: viewModel, - presentDelegate: presentDelegate, - rightSelectorMode: .selector, - imageName: "image_2_24", - title: "market.top.top_collections".localized + topListViewModel: viewModel, + presentDelegate: presentDelegate, + rightSelectorMode: .selector, + imageName: "image_2_24", + title: "market.top.top_collections".localized ) } @@ -30,5 +30,4 @@ class MarketOverviewNftCollectionsDataSource: BaseMarketOverviewTopListDataSourc presentDelegate?.present(viewController: ThemeNavigationController(rootViewController: module)) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsService.swift index a35345dfa9..53b87e144b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsService.swift @@ -1,8 +1,8 @@ -import Foundation import Combine -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class MarketOverviewNftCollectionsService: IMarketListNftTopCollectionDecoratorService { private let baseService: MarketOverviewService @@ -25,8 +25,8 @@ class MarketOverviewNftCollectionsService: IMarketListNftTopCollectionDecoratorS self.baseService = baseService baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync() } @@ -38,21 +38,18 @@ class MarketOverviewNftCollectionsService: IMarketListNftTopCollectionDecoratorS item.marketOverview.collections[timePeriod] ?? [] } } - } extension MarketOverviewNftCollectionsService { - var collectionsObservable: Observable<[NftTopCollection]?> { collectionsRelay.asObservable() } func topCollection(uid: String) -> NftTopCollection? { - guard let collections = collections else { + guard let collections else { return nil } return collections.first { $0.uid == uid } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsViewModel.swift index 6a4b9eec82..5b99a99522 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopNftCollections/MarketOverviewNftCollectionsViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class MarketOverviewNftCollectionsViewModel { private let service: MarketOverviewNftCollectionsService @@ -22,11 +22,9 @@ class MarketOverviewNftCollectionsViewModel { private func sync(collections: [NftTopCollection]?) { listViewItemsRelay.accept(collections.map { $0.enumerated().map { decorator.listViewItem(item: NftCollectionItem(index: $0 + 1, collection: $1)) } }) } - } extension MarketOverviewNftCollectionsViewModel { - var timePeriod: HsTimePeriod { service.timePeriod } @@ -34,17 +32,15 @@ extension MarketOverviewNftCollectionsViewModel { func topCollection(uid: String) -> NftTopCollection? { service.topCollection(uid: uid) } - } extension MarketOverviewNftCollectionsViewModel: IBaseMarketOverviewTopListViewModel { - var listViewItemsDriver: Driver<[MarketModule.ListViewItem]?> { listViewItemsRelay.asDriver() } var selectorTitles: [String] { - MarketNftTopCollectionsModule.selectorValues.map { $0.title } + MarketNftTopCollectionsModule.selectorValues.map(\.title) } var selectorIndex: Int { @@ -54,5 +50,4 @@ extension MarketOverviewNftCollectionsViewModel: IBaseMarketOverviewTopListViewM func onSelect(selectorIndex: Int) { service.timePeriod = MarketNftTopCollectionsModule.selectorValues[selectorIndex] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsService.swift index c797aaa819..e3527e9d20 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsService.swift @@ -1,8 +1,8 @@ -import Foundation import Combine -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class MarketOverviewTopPlatformsService { private let baseService: MarketOverviewService @@ -25,8 +25,8 @@ class MarketOverviewTopPlatformsService { self.baseService = baseService baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync() } @@ -38,20 +38,16 @@ class MarketOverviewTopPlatformsService { item.marketOverview.topPlatforms } } - } extension MarketOverviewTopPlatformsService { - var topPlatformsObservable: Observable<[TopPlatform]?> { topPlatformsRelay.asObservable() } - } -extension MarketOverviewTopPlatformsService: IMarketListTopPlatformDecoratorService { +extension MarketOverviewTopPlatformsService: IMarketListTopPlatformDecoratorService { var currency: Currency { baseService.currency } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsViewModel.swift index 0588d1e23d..4469bb86bc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class MarketOverviewTopPlatformsViewModel { private let service: MarketOverviewTopPlatformsService @@ -22,11 +22,9 @@ class MarketOverviewTopPlatformsViewModel { private func sync(topPlatforms: [TopPlatform]?) { listViewItemsRelay.accept(topPlatforms.map { $0.map { decorator.listViewItem(item: $0) } }) } - } extension MarketOverviewTopPlatformsViewModel { - var timePeriod: HsTimePeriod { service.timePeriod } @@ -34,17 +32,15 @@ extension MarketOverviewTopPlatformsViewModel { func topPlatform(uid: String) -> TopPlatform? { service.topPlatforms?.first { $0.blockchain.uid == uid } } - } extension MarketOverviewTopPlatformsViewModel: IBaseMarketOverviewTopListViewModel { - var listViewItemsDriver: Driver<[MarketModule.ListViewItem]?> { listViewItemsRelay.asDriver() } var selectorTitles: [String] { - MarketTopPlatformsModule.selectorValues.map { $0.title } + MarketTopPlatformsModule.selectorValues.map(\.title) } var selectorIndex: Int { @@ -54,5 +50,4 @@ extension MarketOverviewTopPlatformsViewModel: IBaseMarketOverviewTopListViewMod func onSelect(selectorIndex: Int) { service.timePeriod = MarketTopPlatformsModule.selectorValues[selectorIndex] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostModule.swift index ef057226b2..f13db300bf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostModule.swift @@ -1,9 +1,7 @@ -struct MarketPostModule { - +enum MarketPostModule { static func viewController() -> MarketPostViewController { let service = MarketPostService(marketKit: App.shared.marketKit) let viewModel = MarketPostViewModel(service: service) return MarketPostViewController(viewModel: viewModel, urlManager: UrlManager(inApp: true)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostService.swift index a6d78fcf6c..c68b62618f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import MarketKit import HsExtensions +import MarketKit +import RxRelay +import RxSwift class MarketPostService { private let marketKit: Kit @@ -34,11 +34,9 @@ class MarketPostService { } }.store(in: &tasks) } - } extension MarketPostService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -50,15 +48,12 @@ extension MarketPostService { func refresh() { fetch() } - } extension MarketPostService { - enum State { case loading case loaded(posts: [Post]) case failed(error: Error) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewController.swift index 4f08d71fae..64bc6049f3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import RxSwift -import ThemeKit -import SectionsTableView import ComponentKit import HUD +import RxSwift +import SectionsTableView +import ThemeKit +import UIKit class MarketPostViewController: ThemeViewController { private let viewModel: MarketPostViewModel @@ -26,7 +26,8 @@ class MarketPostViewController: ThemeViewController { super.init() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -110,41 +111,39 @@ class MarketPostViewController: ThemeViewController { private func open(url: String) { urlManager.open(url: url, from: parentNavigationController) } - } extension MarketPostViewController: SectionsDataSource { - private func row(viewItem: MarketPostViewModel.ViewItem) -> RowProtocol { Row( - id: viewItem.title, - height: PostCell.height, - autoDeselect: true, - bind: { cell, _ in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - cell.bind( - header: viewItem.source, - title: viewItem.title, - body: viewItem.body, - time: viewItem.timeAgo - ) - }, - action: { [weak self] _ in - self?.open(url: viewItem.url) - } + id: viewItem.title, + height: PostCell.height, + autoDeselect: true, + bind: { cell, _ in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + cell.bind( + header: viewItem.source, + title: viewItem.title, + body: viewItem.body, + time: viewItem.timeAgo + ) + }, + action: { [weak self] _ in + self?.open(url: viewItem.url) + } ) } func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let viewItems = viewItems { + if let viewItems { for (index, viewItem) in viewItems.enumerated() { let section = Section( - id: "post_\(index)", - headerState: .margin(height: .margin12), - footerState: .margin(height: index == viewItems.count - 1 ? .margin32 : 0), - rows: [row(viewItem: viewItem)] + id: "post_\(index)", + headerState: .margin(height: .margin12), + footerState: .margin(height: index == viewItems.count - 1 ? .margin32 : 0), + rows: [row(viewItem: viewItem)] ) sections.append(section) @@ -153,5 +152,4 @@ extension MarketPostViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewModel.swift index 644e1ad2b6..d93cf1a948 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class MarketPostViewModel { private let service: MarketPostService @@ -26,7 +26,7 @@ class MarketPostViewModel { viewItemsRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .loaded(let posts): + case let .loaded(posts): viewItemsRelay.accept(posts.map { viewItem(post: $0) }) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -39,11 +39,11 @@ class MarketPostViewModel { private func viewItem(post: Post) -> ViewItem { ViewItem( - source: post.source, - title: post.title, - body: post.body, - timeAgo: timeAgo(interval: Date().timeIntervalSince1970 - post.timestamp), - url: post.url + source: post.source, + title: post.title, + body: post.body, + timeAgo: timeAgo(interval: Date().timeIntervalSince1970 - post.timestamp), + url: post.url ) } @@ -65,11 +65,9 @@ class MarketPostViewModel { interval /= 24 return "timestamp.days_ago".localized(interval) } - } extension MarketPostViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { viewItemsRelay.asDriver() } @@ -89,11 +87,9 @@ extension MarketPostViewModel { func refresh() { service.refresh() } - } extension MarketPostViewModel { - struct ViewItem { let source: String let title: String @@ -101,5 +97,4 @@ extension MarketPostViewModel { let timeAgo: String let url: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketService.swift index 89d6cf8910..8ee06c7fce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketService.swift @@ -8,11 +8,9 @@ class MarketService { self.userDefaultsStorage = userDefaultsStorage self.launchScreenManager = launchScreenManager } - } extension MarketService { - var initialTab: MarketModule.Tab { switch launchScreenManager.launchScreen { case .auto: @@ -31,5 +29,4 @@ extension MarketService { func set(tab: MarketModule.Tab) { userDefaultsStorage.set(value: tab.rawValue, for: keyTabIndex) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketListTopPlatformDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketListTopPlatformDecorator.swift index 74a489df80..e9c658f3ff 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketListTopPlatformDecorator.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketListTopPlatformDecorator.swift @@ -1,6 +1,6 @@ +import ComponentKit import Foundation import MarketKit -import ComponentKit protocol IMarketListTopPlatformDecoratorService { var currency: Currency { get } @@ -15,11 +15,9 @@ class MarketListTopPlatformDecorator { init(service: IMarketListTopPlatformDecoratorService) { self.service = service } - } extension MarketListTopPlatformDecorator: IMarketListDecorator { - func listViewItem(item: MarketKit.TopPlatform) -> MarketModule.ListViewItem { let currency = service.currency @@ -40,17 +38,16 @@ extension MarketListTopPlatformDecorator: IMarketListDecorator { let dataValue: MarketModule.MarketDataValue = .diff(diff) return MarketModule.ListViewItem( - uid: item.blockchain.uid, - iconUrl: item.blockchain.type.imageUrl, - iconShape: .square, - iconPlaceholderName: "placeholder_rectangle_32", - leftPrimaryValue: item.blockchain.name, - leftSecondaryValue: protocols, - badge: rank.map { "\($0)" }, - badgeSecondaryValue: rankChange, - rightPrimaryValue: marketCap, - rightSecondaryValue: dataValue + uid: item.blockchain.uid, + iconUrl: item.blockchain.type.imageUrl, + iconShape: .square, + iconPlaceholderName: "placeholder_rectangle_32", + leftPrimaryValue: item.blockchain.name, + leftSecondaryValue: protocols, + badge: rank.map { "\($0)" }, + badgeSecondaryValue: rankChange, + rightPrimaryValue: marketCap, + rightSecondaryValue: dataValue ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsModule.swift index 85c29a743a..2c1bdcdd06 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsModule.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit struct MarketTopPlatformsModule { - static func viewController(timePeriod: HsTimePeriod) -> UIViewController { let service = MarketTopPlatformsService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, appManager: App.shared.appManager, timePeriod: timePeriod) @@ -38,11 +37,9 @@ struct MarketTopPlatformsModule { HsTimePeriod.week1, HsTimePeriod.month1] } - } -extension Array where Element == MarketKit.TopPlatform { - +extension [MarketKit.TopPlatform] { func sorted(sortType: MarketTopPlatformsModule.SortType, timePeriod: HsTimePeriod) -> [TopPlatform] { sorted { lhsPlatform, rhsPlatform in let lhsCap = lhsPlatform.marketCap @@ -53,19 +50,19 @@ extension Array where Element == MarketKit.TopPlatform { switch sortType { case .highestCap, .lowestCap: - guard let lhsCap = lhsCap else { + guard let lhsCap else { return true } - guard let rhsCap = rhsCap else { + guard let rhsCap else { return false } return sortType == .highestCap ? lhsCap > rhsCap : lhsCap < rhsCap case .topGainers, .topLosers: - guard let lhsChange = lhsChange else { + guard let lhsChange else { return true } - guard let rhsChange = rhsChange else { + guard let rhsChange else { return false } @@ -73,5 +70,4 @@ extension Array where Element == MarketKit.TopPlatform { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsService.swift index cdb49b225c..c800c74524 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsService.swift @@ -1,9 +1,9 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import MarketKit +import Foundation import HsExtensions +import MarketKit +import RxRelay +import RxSwift class MarketTopPlatformsService { typealias Item = TopPlatform @@ -27,10 +27,10 @@ class MarketTopPlatformsService { self.timePeriod = timePeriod currencyManager.$baseCurrency - .sink { [weak self] _ in - self?.sync() - } - .store(in: &cancellables) + .sink { [weak self] _ in + self?.sync() + } + .store(in: &cancellables) subscribe(disposeBag, appManager.willEnterForegroundObservable) { [weak self] in self?.sync() } @@ -63,17 +63,15 @@ class MarketTopPlatformsService { } private func syncIfPossible() { - guard case .loaded(let platforms, _, _) = internalState else { + guard case let .loaded(platforms, _, _) = internalState else { return } sync(topPlatforms: platforms, reorder: true) } - } extension MarketTopPlatformsService { - var topPlatforms: [TopPlatform]? { if case let .loaded(data, _, _) = state { return data @@ -81,11 +79,9 @@ extension MarketTopPlatformsService { return nil } - } extension MarketTopPlatformsService: IMarketListService { - var statePublisher: AnyPublisher, Never> { $state } @@ -93,13 +89,10 @@ extension MarketTopPlatformsService: IMarketListService { func refresh() { sync() } - } extension MarketTopPlatformsService: IMarketListTopPlatformDecoratorService { - var currency: Currency { currencyManager.baseCurrency } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewModel.swift index 8cd8e16152..a162b9f5ff 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewModel.swift @@ -10,5 +10,4 @@ class MarketTopPlatformsViewModel { func topPlatform(uid: String) -> TopPlatform? { service.topPlatforms?.first { $0.blockchain.uid == uid } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/TopPlatformsMultiSortHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/TopPlatformsMultiSortHeaderViewModel.swift index 0f4753ca40..f6b9758877 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/TopPlatformsMultiSortHeaderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/TopPlatformsMultiSortHeaderViewModel.swift @@ -8,14 +8,13 @@ class TopPlatformsMultiSortHeaderViewModel { self.service = service self.decorator = decorator } - } extension TopPlatformsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel { - var sortItems: [String] { - MarketTopPlatformsModule.SortType.allCases.map { $0.title } + MarketTopPlatformsModule.SortType.allCases.map(\.title) } + var sortIndex: Int { MarketTopPlatformsModule.SortType.allCases.firstIndex(of: service.sortType) ?? 0 } @@ -23,13 +22,15 @@ extension TopPlatformsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel var leftSelectorItems: [String] { [] } + var leftSelectorIndex: Int { 0 } var rightSelectorItems: [String] { - MarketTopPlatformsModule.selectorValues.map { $0.title } + MarketTopPlatformsModule.selectorValues.map(\.title) } + var rightSelectorIndex: Int { MarketTopPlatformsModule.selectorValues.firstIndex(of: service.timePeriod) ?? 0 } @@ -38,11 +39,9 @@ extension TopPlatformsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel service.sortType = MarketTopPlatformsModule.SortType.allCases[index] } - func onSelectLeft(index: Int) { - } + func onSelectLeft(index _: Int) {} func onSelectRight(index: Int) { service.timePeriod = MarketTopPlatformsModule.selectorValues[index] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewController.swift index 183e9d8fa4..9c29a2f663 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import RxSwift import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class MarketViewController: ThemeViewController { private let viewModel: MarketViewModel @@ -28,7 +28,8 @@ class MarketViewController: ThemeViewController { tabBarItem = UITabBarItem(title: "market.tab_bar_item".localized, image: UIImage(named: "market_2_24"), tag: 0) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -97,11 +98,9 @@ class MarketViewController: ThemeViewController { @objc private func onTapDiscovery() { navigationController?.pushViewController(MarketDiscoveryModule.viewController(), animated: true) } - } extension MarketViewController: IPresentDelegate { - func present(viewController: UIViewController) { navigationController?.present(viewController, animated: true) } @@ -109,5 +108,4 @@ extension MarketViewController: IPresentDelegate { func push(viewController: UIViewController) { navigationController?.pushViewController(viewController, animated: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewModel.swift index 5cf01955a2..8fe4b18e3e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class MarketViewModel { private let service: MarketService @@ -13,11 +13,9 @@ class MarketViewModel { currentTabRelay = BehaviorRelay(value: service.initialTab) } - } extension MarketViewModel { - var currentTabDriver: Driver { currentTabRelay.asDriver() } @@ -30,5 +28,4 @@ extension MarketViewModel { service.set(tab: tab) currentTabRelay.accept(tab) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistModule.swift index bdbd35dbe2..3cccf244f9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistModule.swift @@ -1,18 +1,17 @@ import UIKit struct MarketWatchlistModule { - static func viewController() -> MarketWatchlistViewController { let service = MarketWatchlistService( - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - favoritesManager: App.shared.favoritesManager, - appManager: App.shared.appManager, - userDefaultsStorage: App.shared.userDefaultsStorage + marketKit: App.shared.marketKit, + currencyManager: App.shared.currencyManager, + favoritesManager: App.shared.favoritesManager, + appManager: App.shared.appManager, + userDefaultsStorage: App.shared.userDefaultsStorage ) let watchlistToggleService = MarketWatchlistToggleService( - coinUidService: service, - favoritesManager: App.shared.favoritesManager + coinUidService: service, + favoritesManager: App.shared.favoritesManager ) let decorator = MarketListMarketFieldDecorator(service: service) @@ -22,5 +21,4 @@ struct MarketWatchlistModule { return MarketWatchlistViewController(viewModel: viewModel, listViewModel: listViewModel, headerViewModel: headerViewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewModel.swift index a9c6bab99c..f609521b6b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewModel.swift @@ -4,13 +4,10 @@ class MarketWatchlistViewModel { init(service: MarketWatchlistService) { self.service = service } - } extension MarketWatchlistViewModel { - func onLoad() { service.load() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformHeaderCell.swift index cf1b409642..7874c7426b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformHeaderCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformHeaderCell.swift @@ -41,7 +41,8 @@ class TopPlatformHeaderCell: UITableViewCell { } } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -50,5 +51,4 @@ class TopPlatformHeaderCell: UITableViewCell { descriptionLabel.text = description rightImageView.setImage(withUrlString: imageUrl, placeholder: nil) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformMarketCapFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformMarketCapFetcher.swift index b7acf081f0..9f4a277d90 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformMarketCapFetcher.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformMarketCapFetcher.swift @@ -10,11 +10,9 @@ class TopPlatformMarketCapFetcher { self.currencyManager = currencyManager self.topPlatform = topPlatform } - } extension TopPlatformMarketCapFetcher: IMetricChartFetcher { - var valueType: MetricChartModule.ValueType { .compactCurrencyValue(currencyManager.baseCurrency) } @@ -32,5 +30,4 @@ extension TopPlatformMarketCapFetcher: IMetricChartFetcher { return MetricChartModule.ItemData(items: items, type: .regular) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewModel.swift index 38ef8f644e..4d5acfd65e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewModel.swift @@ -4,11 +4,9 @@ class TopPlatformViewModel { init(service: TopPlatformService) { self.service = service } - } extension TopPlatformViewModel { - var title: String { "top_platform.title".localized(service.topPlatform.blockchain.name) } @@ -20,5 +18,4 @@ extension TopPlatformViewModel { var imageUrl: String { service.topPlatform.blockchain.type.imageUrl } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/DropdownSortHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/DropdownSortHeaderView.swift index f09df9acf9..9cef9beaa9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/DropdownSortHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/DropdownSortHeaderView.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit -import RxSwift import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit protocol IDropdownSortHeaderViewModel: AnyObject { var dropdownTitle: String { get } @@ -67,14 +67,15 @@ class DropdownSortHeaderView: UITableViewHeaderFooterView { subscribe(disposeBag, viewModel.sortDirectionAscendingDriver) { [weak self] in self?.syncSortButton(ascending: $0) } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func onTapDropdownButton() { let alertController = AlertRouter.module( - title: viewModel.dropdownTitle, - viewItems: viewModel.dropdownViewItems + title: viewModel.dropdownTitle, + viewItems: viewModel.dropdownViewItems ) { [weak self] index in self?.viewModel.onSelectDropdown(index: index) } @@ -93,5 +94,4 @@ class DropdownSortHeaderView: UITableViewHeaderFooterView { private func syncSortButton(ascending: Bool) { sortButton.set(image: UIImage(named: ascending ? "arrow_medium_2_up_20" : "arrow_medium_2_down_20")) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/GradientPercentCircle.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/GradientPercentCircle.swift index 76d47f4593..3fb4b9fe38 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/GradientPercentCircle.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/GradientPercentCircle.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class GradientPercentCircle: UIView { static let width: CGFloat = 44 @@ -25,7 +25,8 @@ class GradientPercentCircle: UIView { layer.addSublayer(gradientLayer) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -73,14 +74,12 @@ class GradientPercentCircle: UIView { layer.removeAllAnimations() } } - } extension GradientPercentCircle { - public func set(value: CGFloat?, animated: Bool = true) { guard let percentValue = value else { - if currentValue != nil { // alpha change from current to nil (hide) + if currentValue != nil { // alpha change from current to nil (hide) hide(layer: gradientLayer, animated: animated) currentValue = nil } @@ -89,15 +88,14 @@ extension GradientPercentCircle { } let value = percentValue / 100 - guard currentValue != nil else { // alpha change from nil to new (show) + guard currentValue != nil else { // alpha change from nil to new (show) show(layer: gradientLayer, value: value, animated: animated) currentValue = value return } - move(layer: gradientLayer, toValue: value, animated: animated) // move gradient position + move(layer: gradientLayer, toValue: value, animated: animated) // move gradient position currentValue = value } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMetricView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMetricView.swift index cad31a9096..edede2a9d5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMetricView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMetricView.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit import Chart -import ThemeKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class MarketMetricView: UIView { static let height: CGFloat = 104 @@ -14,12 +14,12 @@ class MarketMetricView: UIView { private let chartView: RateChartView private let button = UIButton() - var onTap: (() -> ())? { + var onTap: (() -> Void)? { didSet { button.isUserInteractionEnabled = onTap != nil } } - + var alreadyHasData: Bool = false init(configuration: ChartConfiguration) { @@ -90,7 +90,8 @@ class MarketMetricView: UIView { diffLabel.font = .subhead1 } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -107,11 +108,9 @@ class MarketMetricView: UIView { @objc private func didTapButton() { onTap?() } - } extension MarketMetricView { - var title: String? { get { titleLabel.text } set { titleLabel.text = newValue } @@ -139,7 +138,7 @@ extension MarketMetricView { diffLabel.set(value: diff) chartView.setCurve(colorType: trend.chartColorType) - if let chartData = chartData { + if let chartData { chartView.set(chartData: chartData, animated: alreadyHasData) alreadyHasData = true } else { @@ -155,7 +154,7 @@ extension MarketMetricView { diffLabel.set(text: diff, color: diffColor) chartView.setCurve(colorType: trend.chartColorType) - if let chartData = chartData { + if let chartData { chartView.set(chartData: chartData, indicators: [], animated: alreadyHasData) alreadyHasData = true } else { @@ -170,5 +169,4 @@ extension MarketMetricView { alreadyHasData = false } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderView.swift index 639681186a..3ad3445173 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderView.swift @@ -1,8 +1,8 @@ -import UIKit -import UIExtensions -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIExtensions +import UIKit protocol IMarketMultiSortHeaderViewModel { var sortItems: [String] { get } @@ -92,16 +92,17 @@ class MarketMultiSortHeaderView: UITableViewHeaderFooterView { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func tapSortButton() { let alertController = AlertRouter.module( - title: "market.sort_by".localized, - viewItems: viewModel.sortItems.enumerated().map { (index, sortingField) in - AlertViewItem(text: sortingField, selected: index == viewModel.sortIndex) - } + title: "market.sort_by".localized, + viewItems: viewModel.sortItems.enumerated().map { index, sortingField in + AlertViewItem(text: sortingField, selected: index == viewModel.sortIndex) + } ) { [weak self] index in self?.viewModel.onSelectSort(index: index) self?.syncSortButtonTitle() @@ -113,5 +114,4 @@ class MarketMultiSortHeaderView: UITableViewHeaderFooterView { private func syncSortButtonTitle() { sortButton.setTitle(viewModel.sortItems[viewModel.sortIndex], for: .normal) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderViewModel.swift index 5321da452d..dde0dcb384 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderViewModel.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift protocol IMarketMultiSortHeaderService: AnyObject { var marketTop: MarketModule.MarketTop { get set } @@ -21,28 +21,29 @@ class MarketMultiSortHeaderViewModel { self.service = service self.decorator = decorator } - } extension MarketMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel { - var sortItems: [String] { - MarketModule.SortingField.allCases.map { $0.title } + MarketModule.SortingField.allCases.map(\.title) } + var sortIndex: Int { MarketModule.SortingField.allCases.firstIndex(of: service.sortingField) ?? 0 } var leftSelectorItems: [String] { - MarketModule.MarketTop.allCases.map { $0.title } + MarketModule.MarketTop.allCases.map(\.title) } + var leftSelectorIndex: Int { MarketModule.MarketTop.allCases.firstIndex(of: service.marketTop) ?? 0 } var rightSelectorItems: [String] { - MarketModule.MarketField.allCases.map { $0.title } + MarketModule.MarketField.allCases.map(\.title) } + var rightSelectorIndex: Int { MarketModule.MarketField.allCases.firstIndex(of: decorator.marketField) ?? 0 } @@ -58,5 +59,4 @@ extension MarketMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel { func onSelectRight(index: Int) { decorator.marketField = MarketModule.MarketField.allCases[index] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderView.swift index 9be396fc14..fa80b293c4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderView.swift @@ -1,10 +1,10 @@ -import UIKit -import UIExtensions -import ThemeKit -import SnapKit import ComponentKit -import RxSwift import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIExtensions +import UIKit class MarketSingleSortHeaderView: UITableViewHeaderFooterView { static let height: CGFloat = .heightSingleLineCell @@ -61,7 +61,8 @@ class MarketSingleSortHeaderView: UITableViewHeaderFooterView { subscribe(disposeBag, viewModel.sortDirectionDriver) { [weak self] in self?.syncSortButton(ascending: $0) } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -72,5 +73,4 @@ class MarketSingleSortHeaderView: UITableViewHeaderFooterView { private func syncSortButton(ascending: Bool) { sortButton.set(image: UIImage(named: ascending ? "arrow_medium_2_up_20" : "arrow_medium_2_down_20")) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderViewModel.swift index 01be5dc8b2..1799b6c29b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift protocol IMarketSingleSortHeaderService: AnyObject { var sortDirectionAscending: Bool { get set } @@ -24,11 +24,9 @@ class MarketSingleSortHeaderViewModel { sortDirectionRelay = BehaviorRelay(value: service.sortDirectionAscending) } - } extension MarketSingleSortHeaderViewModel { - var allFields: [String] { decorator.allFields } @@ -53,5 +51,4 @@ extension MarketSingleSortHeaderViewModel { func onSelectField(index: Int) { decorator.setCurrentField(index: index) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderView.swift index 7c2f03fb16..2217130dce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderView.swift @@ -1,10 +1,10 @@ -import UIKit -import UIExtensions -import ThemeKit -import SnapKit import ComponentKit -import RxSwift import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIExtensions +import UIKit class MarketTvlSortHeaderView: UITableViewHeaderFooterView { static let height: CGFloat = .heightSingleLineCell @@ -71,14 +71,15 @@ class MarketTvlSortHeaderView: UITableViewHeaderFooterView { subscribe(disposeBag, viewModel.marketTvlFieldDriver) { [weak self] in self?.syncMarketTvlFieldButton(marketTvlField: $0) } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func onTapDropdownButton() { let alertController = AlertRouter.module( - title: "market.global.tvl_in_defi.filter_by_chain".localized, - viewItems: viewModel.platformFieldViewItems + title: "market.global.tvl_in_defi.filter_by_chain".localized, + viewItems: viewModel.platformFieldViewItems ) { [weak self] index in self?.viewModel.onSelectMarketPlatformField(index: index) } @@ -111,5 +112,4 @@ class MarketTvlSortHeaderView: UITableViewHeaderFooterView { private func syncSortButton(ascending: Bool) { sortButton.set(image: UIImage(named: ascending ? "arrow_medium_2_up_20" : "arrow_medium_2_down_20")) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderViewModel.swift index 668833c42c..e64773cc15 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class MarketTvlSortHeaderViewModel { private let service: MarketGlobalTvlMetricService @@ -18,11 +18,9 @@ class MarketTvlSortHeaderViewModel { sortDirectionAscendingRelay = BehaviorRelay(value: service.sortDirectionAscending) marketTvlFieldRelay = BehaviorRelay(value: service.marketTvlField) } - } extension MarketTvlSortHeaderViewModel { - var platformFieldViewItems: [AlertViewItem] { MarketModule.MarketPlatformField.allCases.map { platformField in AlertViewItem(text: platformField.title, selected: service.marketPlatformField == platformField) @@ -74,5 +72,4 @@ extension MarketTvlSortHeaderViewModel { service.marketPlatformField = MarketModule.MarketPlatformField.allCases[index] platformFieldRelay.accept(service.marketPlatformField.title) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartFactory.swift index a8a63b16a5..a1e9606788 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartFactory.swift @@ -1,9 +1,9 @@ +import Chart import Foundation import MarketKit -import Chart class MetricChartFactory { - static private let noChangesLimitPercent: Decimal = 0.2 + private static let noChangesLimitPercent: Decimal = 0.2 private let dateFormatter = DateFormatter() @@ -12,14 +12,14 @@ class MetricChartFactory { } private func format(value: Decimal?, valueType: MetricChartModule.ValueType, exactlyValue: Bool = false) -> String? { - guard let value = value else { + guard let value else { return nil } switch valueType { case .percent: return ValueFormatter.instance.format(percentValue: value, showSign: false) - case .currencyValue(let currency): + case let .currencyValue(currency): return ValueFormatter.instance.formatFull(currency: currency, value: value) case .counter: if exactlyValue { @@ -27,7 +27,7 @@ class MetricChartFactory { } else { return ValueFormatter.instance.formatShort(value: value) } - case .compactCoinValue(let coin): + case let .compactCoinValue(coin): let valueString: String? if exactlyValue { valueString = value.description @@ -35,7 +35,7 @@ class MetricChartFactory { valueString = ValueFormatter.instance.formatShort(value: value) } return [valueString, coin.code].compactMap { $0 }.joined(separator: " ") - case .compactCurrencyValue(let currency): + case let .compactCurrencyValue(currency): if exactlyValue { return ValueFormatter.instance.formatFull(currency: currency, value: value) } else { @@ -43,11 +43,9 @@ class MetricChartFactory { } } } - } extension MetricChartFactory { - func convert(itemData: MetricChartModule.ItemData, valueType: MetricChartModule.ValueType) -> ChartModule.ViewItem? { guard let firstItem = itemData.items.first, let lastItem = itemData.items.last else { return nil @@ -64,7 +62,7 @@ extension MetricChartFactory { endTimestamp = lastItem.timestamp } - let values = itemData.items.map { $0.value } + let values = itemData.items.map(\.value) var min = values.min() var max = values.max() @@ -87,13 +85,13 @@ extension MetricChartFactory { if let first = itemData.indicators[MarketGlobalModule.dominance]?.first, let last = itemData.indicators[MarketGlobalModule.dominance]?.last { rightSideMode = .dominance(value: last, diff: (last - first) / first * 100) } - case .aggregated(let aggregatedValue): + case let .aggregated(aggregatedValue): value = format(value: aggregatedValue, valueType: valueType) chartTrend = .neutral } var chartItems = [ChartItem]() - for index in 0.. ChartModule.SelectedPointViewItem? { + func selectedPointViewItem(chartItem: ChartItem, firstChartItem _: ChartItem?, valueType: MetricChartModule.ValueType) -> ChartModule.SelectedPointViewItem? { guard let value = chartItem.indicators[ChartData.rate] else { return nil } @@ -144,10 +143,9 @@ extension MetricChartFactory { } return ChartModule.SelectedPointViewItem( - value: formattedValue, - date: formattedDate, - rightSideMode: rightSideMode + value: formattedValue, + date: formattedDate, + rightSideMode: rightSideMode ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartModule.swift index 7474b38c6e..f6315c047d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartModule.swift @@ -1,7 +1,7 @@ -import Combine -import UIKit import Chart +import Combine import MarketKit +import UIKit protocol IMetricChartFetcher { var valueType: MetricChartModule.ValueType { get } @@ -11,7 +11,6 @@ protocol IMetricChartFetcher { } extension IMetricChartFetcher { - var intervals: [HsTimePeriod] { [.day1, .week1, .week2, .month1, .month3, .month6, .year1] } @@ -19,11 +18,9 @@ extension IMetricChartFetcher { var needUpdatePublisher: AnyPublisher { Empty().eraseToAnyPublisher() } - } -class MetricChartModule { - +enum MetricChartModule { enum ValueType { case percent case counter @@ -57,12 +54,10 @@ class MetricChartModule { self.value = value self.timestamp = timestamp } - } struct OverriddenValue { let value: String let description: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartService.swift index dd2fe7dfc1..1ef83da6ea 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartService.swift @@ -1,7 +1,7 @@ import Combine -import UIKit -import MarketKit import HsExtensions +import MarketKit +import UIKit class MetricChartService { private var tasks = Set() @@ -26,8 +26,8 @@ class MetricChartService { self.interval = interval chartFetcher.needUpdatePublisher - .sink { [weak self] in self?.fetchChartData() } - .store(in: &cancellables) + .sink { [weak self] in self?.fetchChartData() } + .store(in: &cancellables) } func fetchChartData() { @@ -50,15 +50,12 @@ class MetricChartService { } }.store(in: &tasks) } - } extension MetricChartService { - var valueType: MetricChartModule.ValueType { chartFetcher.valueType } var intervals: [HsTimePeriod] { chartFetcher.intervals } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewController.swift index 7c189d8652..02367fc1d3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewController.swift @@ -1,11 +1,11 @@ -import UIKit +import Chart +import ComponentKit +import HUD import RxSwift -import ThemeKit import SectionsTableView import SnapKit -import HUD -import Chart -import ComponentKit +import ThemeKit +import UIKit class MetricChartViewController: ThemeActionSheetController { private let viewModel: MetricChartViewModel @@ -27,15 +27,16 @@ class MetricChartViewController: ThemeActionSheetController { chartCell = ChartCell(viewModel: viewModel, configuration: configuration) chartRow = StaticRow( - cell: chartCell, - id: "chartView", - height: chartCell.cellHeight + cell: chartCell, + id: "chartView", + height: chartCell.cellHeight ) super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -48,9 +49,9 @@ class MetricChartViewController: ThemeActionSheetController { } titleView.bind( - image: .local(name: "chart_2_24", tint: .warning), - title: bottomSheetTitle, - viewController: self + image: .local(name: "chart_2_24", tint: .warning), + title: bottomSheetTitle, + viewController: self ) view.addSubview(tableView) @@ -80,25 +81,20 @@ class MetricChartViewController: ThemeActionSheetController { tableView.beginUpdates() tableView.endUpdates() } - } extension MetricChartViewController { - private var chartSection: SectionProtocol { Section( - id: "chart", - footerState: .margin(height: .margin16), - rows: [chartRow] + id: "chart", + footerState: .margin(height: .margin16), + rows: [chartRow] ) } - } extension MetricChartViewController: SectionsDataSource { - public func buildSections() -> [SectionProtocol] { [chartSection] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewModel.swift index 2826f363ee..d3e14f9bb0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MetricChart/MetricChartViewModel.swift @@ -1,11 +1,11 @@ -import Foundation -import Combine -import RxSwift -import RxRelay -import RxCocoa -import MarketKit import Chart +import Combine +import Foundation import HUD +import MarketKit +import RxCocoa +import RxRelay +import RxSwift class MetricChartViewModel { private let service: MetricChartService @@ -24,12 +24,12 @@ class MetricChartViewModel { self.factory = factory service.$interval - .sink { [weak self] in self?.sync(interval: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(interval: $0) } + .store(in: &cancellables) service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) sync(interval: service.interval) sync(state: service.state) @@ -48,7 +48,7 @@ class MetricChartViewModel { loadingRelay.accept(false) errorRelay.accept(true) chartInfoRelay.accept(nil) - case .completed(let itemData): + case let .completed(itemData): loadingRelay.accept(false) if let viewItem = factory.convert(itemData: itemData, valueType: service.valueType) { @@ -60,11 +60,9 @@ class MetricChartViewModel { } } } - } extension MetricChartViewModel: IChartViewModel { - var pointSelectedItemDriver: Driver { pointSelectedItemRelay.asDriver() } @@ -111,28 +109,24 @@ extension MetricChartViewModel: IChartViewModel { func retry() { service.fetchChartData() } - } extension MetricChartViewModel: IChartViewTouchDelegate { + public func touchDown() {} - public func touchDown() { - } - - public func select(item: ChartItem, indicators: [ChartIndicator]) { + public func select(item: ChartItem, indicators _: [ChartIndicator]) { HapticGenerator.instance.notification(.feedback(.soft)) pointSelectedItemRelay.accept( - factory.selectedPointViewItem( - chartItem: item, - firstChartItem: chartInfoRelay.value?.chartData.items.first, - valueType: service.valueType - ) + factory.selectedPointViewItem( + chartItem: item, + firstChartItem: chartInfoRelay.value?.chartData.items.first, + valueType: service.valueType + ) ) } public func touchUp() { pointSelectedItemRelay.accept(nil) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderView.swift index 0688ce8b39..944d43b177 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderView.swift @@ -1,10 +1,10 @@ -import UIKit -import RxSwift -import RxCocoa -import ThemeKit -import SnapKit import ComponentKit import HUD +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class NftHeaderView: UITableViewHeaderFooterView { static var height: CGFloat = HeaderAmountView.height + .heightCell48 @@ -85,12 +85,13 @@ class NftHeaderView: UITableViewHeaderFooterView { subscribe(disposeBag, viewModel.playHapticSignal) { [weak self] in self?.playHaptic() } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } private func sync(viewItem: NftHeaderViewModel.ViewItem?) { - guard let viewItem = viewItem else { + guard let viewItem else { return } @@ -101,5 +102,4 @@ class NftHeaderView: UITableViewHeaderFooterView { private func playHaptic() { HapticGenerator.instance.notification(.feedback(.soft)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderViewModel.swift index 6a448636aa..b61736b346 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftHeaderViewModel.swift @@ -1,13 +1,13 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class NftHeaderViewModel { private let service: NftService private let disposeBag = DisposeBag() private let viewItemRelay = BehaviorRelay(value: nil) - private let playHapticRelay = PublishRelay<()>() + private let playHapticRelay = PublishRelay() init(service: NftService) { self.service = service @@ -34,10 +34,10 @@ class NftHeaderViewModel { } return ViewItem( - amount: amount, - amountExpired: balanceHidden ? false : totalItem.expired, - convertedValue: convertedValue, - convertedValueExpired: balanceHidden ? false : totalItem.convertedValueExpired + amount: amount, + amountExpired: balanceHidden ? false : totalItem.expired, + convertedValue: convertedValue, + convertedValueExpired: balanceHidden ? false : totalItem.convertedValueExpired ) } @@ -55,16 +55,14 @@ class NftHeaderViewModel { case .average30d: return "nft_collections.average_30d".localized } } - } extension NftHeaderViewModel { - var viewItemDriver: Driver { viewItemRelay.asDriver() } - var playHapticSignal: Signal<()> { + var playHapticSignal: Signal { playHapticRelay.asSignal() } @@ -89,16 +87,13 @@ extension NftHeaderViewModel { func onSelectPriceType(index: Int) { service.mode = NftService.Mode.allCases[index] } - } extension NftHeaderViewModel { - struct ViewItem { let amount: String? let amountExpired: Bool let convertedValue: String? let convertedValueExpired: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftModule.swift index 9ffe41edaa..d2d2c2ae9b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftModule.swift @@ -1,13 +1,12 @@ -import UIKit import ThemeKit +import UIKit struct NftModule { - static func viewController() -> UIViewController? { let coinPriceService = WalletCoinPriceService( - tag: "nft", - currencyManager: App.shared.currencyManager, - marketKit: App.shared.marketKit + tag: "nft", + currencyManager: App.shared.currencyManager, + marketKit: App.shared.marketKit ) guard let account = App.shared.accountManager.activeAccount else { @@ -15,13 +14,13 @@ struct NftModule { } let service = NftService( - account: account, - nftAdapterManager: App.shared.nftAdapterManager, - nftMetadataManager: App.shared.nftMetadataManager, - nftMetadataSyncer: App.shared.nftMetadataSyncer, - balanceHiddenManager: App.shared.balanceHiddenManager, - balanceConversionManager: App.shared.balanceConversionManager, - coinPriceService: coinPriceService + account: account, + nftAdapterManager: App.shared.nftAdapterManager, + nftMetadataManager: App.shared.nftMetadataManager, + nftMetadataSyncer: App.shared.nftMetadataSyncer, + balanceHiddenManager: App.shared.balanceHiddenManager, + balanceConversionManager: App.shared.balanceConversionManager, + coinPriceService: coinPriceService ) coinPriceService.delegate = service @@ -31,5 +30,4 @@ struct NftModule { return NftViewController(viewModel: viewModel, headerViewModel: headerViewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftService.swift index eaa749864a..1c3aa62154 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class NftService { private let account: Account @@ -95,20 +95,19 @@ class NftService { metadataMap[nftKey.blockchainType] = nftMetadataManager.addressMetadata(nftKey: nftKey) adapter.nftRecordsObservable - .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] records in - self?.handleUpdated(records: records, blockchainType: nftKey.blockchainType) - }) - .disposed(by: adapterDisposeBag) - - } - - nftMetadataManager.addressMetadataObservable .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] nftKey, addressMetadata in - self?.handleUpdated(addressMetadata: addressMetadata, nftKey: nftKey) + .subscribe(onNext: { [weak self] records in + self?.handleUpdated(records: records, blockchainType: nftKey.blockchainType) }) .disposed(by: adapterDisposeBag) + } + + nftMetadataManager.addressMetadataObservable + .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onNext: { [weak self] nftKey, addressMetadata in + self?.handleUpdated(addressMetadata: addressMetadata, nftKey: nftKey) + }) + .disposed(by: adapterDisposeBag) _syncNftItemMap() } @@ -175,8 +174,8 @@ class NftService { _syncItems() coinPriceService.set( - coinUids: allCoinUids(items: items), - conversionCoinUids: Set(balanceConversionManager.conversionTokens.map { $0.coin.uid }) + coinUids: allCoinUids(items: items), + conversionCoinUids: Set(balanceConversionManager.conversionTokens.map(\.coin.uid)) ) } @@ -191,35 +190,33 @@ class NftService { let collectionMetadata = nftCollectionItem.metadata return Item( - uid: providerCollectionUid, - providerCollectionUid: collectionMetadata?.providerUid, - imageUrl: collectionMetadata?.thumbnailImageUrl, - name: collectionMetadata?.name ?? providerCollectionUid, - count: nftCollectionItem.nftItems.map { - $0.record.balance - } - .reduce(0, +), - assetItems: nftCollectionItem.nftItems.map { nftItem in - let record = nftItem.record - let metadata = nftItem.assetMetadata - - var price: NftPrice? - - switch mode { - case .lastSale: price = metadata?.lastSalePrice - case .average7d: price = collectionMetadata?.averagePrice7d - case .average30d: price = collectionMetadata?.averagePrice30d - } - - return AssetItem( - nftUid: record.nftUid, - imageUrl: metadata?.previewImageUrl, - name: metadata?.name ?? "#\(record.nftUid.tokenId)", - count: record.balance, - onSale: metadata?.onSale ?? false, - price: price - ) + uid: providerCollectionUid, + providerCollectionUid: collectionMetadata?.providerUid, + imageUrl: collectionMetadata?.thumbnailImageUrl, + name: collectionMetadata?.name ?? providerCollectionUid, + count: nftCollectionItem.nftItems.map(\.record.balance) + .reduce(0, +), + assetItems: nftCollectionItem.nftItems.map { nftItem in + let record = nftItem.record + let metadata = nftItem.assetMetadata + + var price: NftPrice? + + switch mode { + case .lastSale: price = metadata?.lastSalePrice + case .average7d: price = collectionMetadata?.averagePrice7d + case .average30d: price = collectionMetadata?.averagePrice30d } + + return AssetItem( + nftUid: record.nftUid, + imageUrl: metadata?.previewImageUrl, + name: metadata?.name ?? "#\(record.nftUid.tokenId)", + count: record.balance, + onSale: metadata?.onSale ?? false, + price: price + ) + } ) } @@ -249,10 +246,10 @@ class NftService { } totalItem = TotalItem( - currencyValue: CurrencyValue(currency: coinPriceService.currency, value: total), - expired: false, - convertedValue: convertedValue, - convertedValueExpired: convertedValueExpired + currencyValue: CurrencyValue(currency: coinPriceService.currency, value: total), + expired: false, + convertedValue: convertedValue, + convertedValueExpired: convertedValueExpired ) } @@ -261,11 +258,9 @@ class NftService { item.name.caseInsensitiveCompare(item2.name) == .orderedAscending } } - } extension NftService: IWalletCoinPriceServiceDelegate { - func didUpdateBaseCurrency() { queue.async { self.updatePriceItems(items: self.items, map: self.coinPriceService.itemMap(coinUids: Array(self.allCoinUids(items: self.items)))) @@ -281,11 +276,9 @@ extension NftService: IWalletCoinPriceServiceDelegate { self.syncTotalItem() } } - } extension NftService { - var itemsObservable: Observable<[Item]> { itemsRelay.asObservable() } @@ -313,11 +306,9 @@ extension NftService { func toggleConversionCoin() { balanceConversionManager.toggleConversionToken() } - } extension NftService { - struct NftCollectionItem { let metadata: NftCollectionShortMetadata? var nftItems: [NftItem] @@ -363,7 +354,6 @@ extension NftService { self.onSale = onSale self.price = price } - } struct TotalItem { @@ -378,5 +368,4 @@ extension NftService { case average7d case average30d } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewController.swift index 6b75a8de22..ae4f4180a5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewController.swift @@ -1,11 +1,11 @@ -import UIKit +import ComponentKit import Foundation -import RxSwift +import Kingfisher import RxCocoa -import ThemeKit -import ComponentKit +import RxSwift import SectionsTableView -import Kingfisher +import ThemeKit +import UIKit class NftViewController: ThemeViewController { private let viewModel: NftViewModel @@ -30,7 +30,8 @@ class NftViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -110,67 +111,65 @@ class NftViewController: ThemeViewController { let module = NftAssetModule.viewController(providerCollectionUid: providerCollectionUid, nftUid: viewItem.nftUid) present(ThemeNavigationController(rootViewController: module), animated: true) } - } extension NftViewController: SectionsDataSource { - private func row(leftViewItem: NftDoubleCell.ViewItem, rightViewItem: NftDoubleCell.ViewItem?, isLast: Bool) -> RowProtocol { Row( - id: "token-\(leftViewItem.nftUid.uid)-\(rightViewItem?.nftUid.uid ?? "nil")", - hash: "\(leftViewItem.hash)-\(rightViewItem?.hash ?? "nil")", - dynamicHeight: { width in - NftDoubleCell.height(containerWidth: width, isLast: isLast) - }, - bind: { cell, _ in - cell.bind(leftViewItem: leftViewItem, rightViewItem: rightViewItem) { [weak self] viewItem in - self?.openAsset(viewItem: viewItem) - } + id: "token-\(leftViewItem.nftUid.uid)-\(rightViewItem?.nftUid.uid ?? "nil")", + hash: "\(leftViewItem.hash)-\(rightViewItem?.hash ?? "nil")", + dynamicHeight: { width in + NftDoubleCell.height(containerWidth: width, isLast: isLast) + }, + bind: { cell, _ in + cell.bind(leftViewItem: leftViewItem, rightViewItem: rightViewItem) { [weak self] viewItem in + self?.openAsset(viewItem: viewItem) } + } ) } - private func row(viewItem: NftViewModel.ViewItem, expanded: Bool, index: Int) -> RowProtocol { + private func row(viewItem: NftViewModel.ViewItem, expanded: Bool, index _: Int) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .image32 { (component: ImageComponent) -> () in - component.imageView.cornerRadius = .cornerRadius4 - component.imageView.layer.cornerCurve = .continuous - component.imageView.backgroundColor = .themeSteel20 - component.imageView.kf.setImage( - with: viewItem.imageUrl.flatMap { URL(string: $0) }, - options: [.onlyLoadFirstFrame] - ) - }, - .text { (component: TextComponent) -> () in - component.font = .headline2 - component.textColor = .themeLeah - component.text = viewItem.name - }, - .text { (component: TextComponent) -> () in - component.font = .subhead1 - component.textColor = .themeGray - component.text = viewItem.count - component.setContentHuggingPriority(.required, for: .horizontal) - component.setContentCompressionResistancePriority(.required, for: .horizontal) - }, - .margin8, - .image20 { (component: ImageComponent) -> () in - component.imageView.image = UIImage(named: expanded ? "arrow_big_up_20" : "arrow_big_down_20")?.withTintColor(.themeGray) - } - ]), - tableView: tableView, - id: "collection-\(viewItem.uid)", - hash: "\(viewItem.name)-\(viewItem.count)-\(expanded)", - height: .heightCell56, - bind: { cell in - cell.set(backgroundStyle: .transparent) - cell.wrapperView.backgroundColor = .themeTyler - cell.selectionStyle = .none + rootElement: .hStack([ + .image32 { (component: ImageComponent) in + component.imageView.cornerRadius = .cornerRadius4 + component.imageView.layer.cornerCurve = .continuous + component.imageView.backgroundColor = .themeSteel20 + component.imageView.kf.setImage( + with: viewItem.imageUrl.flatMap { URL(string: $0) }, + options: [.onlyLoadFirstFrame] + ) }, - action: { [weak self] in - self?.viewModel.onTap(uid: viewItem.uid) - } + .text { (component: TextComponent) in + component.font = .headline2 + component.textColor = .themeLeah + component.text = viewItem.name + }, + .text { (component: TextComponent) in + component.font = .subhead1 + component.textColor = .themeGray + component.text = viewItem.count + component.setContentHuggingPriority(.required, for: .horizontal) + component.setContentCompressionResistancePriority(.required, for: .horizontal) + }, + .margin8, + .image20 { (component: ImageComponent) in + component.imageView.image = UIImage(named: expanded ? "arrow_big_up_20" : "arrow_big_down_20")?.withTintColor(.themeGray) + }, + ]), + tableView: tableView, + id: "collection-\(viewItem.uid)", + hash: "\(viewItem.name)-\(viewItem.count)-\(expanded)", + height: .heightCell56, + bind: { cell in + cell.set(backgroundStyle: .transparent) + cell.wrapperView.backgroundColor = .themeTyler + cell.selectionStyle = .none + }, + action: { [weak self] in + self?.viewModel.onTap(uid: viewItem.uid) + } ) } @@ -186,20 +185,20 @@ extension NftViewController: SectionsDataSource { let doubleRowCount = viewItem.assetViewItems.count / 2 let hasSingleRow = viewItem.assetViewItems.count % 2 == 1 - for i in 0.. [SectionProtocol] { [ Section( - id: "main", - headerState: viewItems.isEmpty ? .margin(height: 0) : .static(view: headerView, height: NftHeaderView.height), - footerState: .marginColor(height: .margin32, color: .clear), - rows: rows(viewItems: viewItems) - ) + id: "main", + headerState: viewItems.isEmpty ? .margin(height: 0) : .static(view: headerView, height: NftHeaderView.height), + footerState: .marginColor(height: .margin32, color: .clear), + rows: rows(viewItems: viewItems) + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewModel.swift index d9f0337f24..7305bd86f8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Nft/NftViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class NftViewModel { private let service: NftService @@ -28,13 +28,13 @@ class NftViewModel { private func viewItem(item: NftService.Item) -> ViewItem { ViewItem( - uid: item.uid, - imageUrl: item.imageUrl, - name: item.name, - count: "\(item.count)", - assetViewItems: item.assetItems.map { - assetViewItem(item: item, assetItem: $0) - } + uid: item.uid, + imageUrl: item.imageUrl, + name: item.name, + count: "\(item.count)", + assetViewItems: item.assetItems.map { + assetViewItem(item: item, assetItem: $0) + } ) } @@ -54,21 +54,19 @@ class NftViewModel { } return NftDoubleCell.ViewItem( - providerCollectionUid: item.providerCollectionUid, - nftUid: assetItem.nftUid, - imageUrl: assetItem.imageUrl, - name: assetItem.name, - count: assetItem.count == 1 ? nil : "\(assetItem.count)", - onSale: assetItem.onSale, - coinPrice: coinPrice, - fiatPrice: fiatPrice + providerCollectionUid: item.providerCollectionUid, + nftUid: assetItem.nftUid, + imageUrl: assetItem.imageUrl, + name: assetItem.name, + count: assetItem.count == 1 ? nil : "\(assetItem.count)", + onSale: assetItem.onSale, + coinPrice: coinPrice, + fiatPrice: fiatPrice ) } - } extension NftViewModel { - var viewItemsDriver: Driver<[ViewItem]> { viewItemsRelay.asDriver() } @@ -92,11 +90,9 @@ extension NftViewModel { expandedUidsRelay.accept(expandedUids) } - } extension NftViewModel { - struct ViewItem { let uid: String let imageUrl: String? @@ -104,5 +100,4 @@ extension NftViewModel { let count: String let assetViewItems: [NftDoubleCell.ViewItem] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetCellFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetCellFactory.swift index 795f8a45f8..3670e899bf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetCellFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetCellFactory.swift @@ -5,7 +5,7 @@ import UIKit class NftAssetCellFactory { weak var parentNavigationController: UINavigationController? - func action(viewItem: NftActivityViewModel.EventViewItem) -> (() -> Void)? { nil } + func action(viewItem _: NftActivityViewModel.EventViewItem) -> (() -> Void)? { nil } func cellElement(viewItem: NftActivityViewModel.EventViewItem) -> CellBuilderNew.CellElement { .vStackCentered([ @@ -34,7 +34,6 @@ class NftAssetCellFactory { } extension NftAssetCellFactory: INftActivityCellFactory { - func row(tableView: UIKit.UITableView, viewItem: NftActivityViewModel.EventViewItem, index: Int, onReachBottom: (() -> Void)? = nil) -> RowProtocol { CellBuilderNew.row( rootElement: cellElement(viewItem: viewItem), diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetImageCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetImageCell.swift index 855fa99fde..e2258b381c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetImageCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetImageCell.swift @@ -1,5 +1,5 @@ -import UIKit import ComponentKit +import UIKit class NftAssetImageCell: UITableViewCell { private static let horizontalMargin: CGFloat = .margin16 @@ -17,7 +17,8 @@ class NftAssetImageCell: UITableViewCell { nftImageView.layer.cornerCurve = .continuous } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -35,12 +36,10 @@ class NftAssetImageCell: UITableViewCell { var currentImage: UIImage? { nftImageView.currentImage } - } extension NftAssetImageCell { - - static func height(containerWidth: CGFloat, maxHeight: CGFloat, ratio: CGFloat) -> CGFloat { + static func height(containerWidth: CGFloat, maxHeight _: CGFloat, ratio: CGFloat) -> CGFloat { let imageWidth = max(0, containerWidth - 2 * horizontalMargin) return min(120, imageWidth * ratio) } @@ -49,5 +48,4 @@ extension NftAssetImageCell { let imageWidth = max(0, containerWidth - 2 * horizontalMargin) return imageWidth * ratio } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetModule.swift index 2abac20ec7..6e37173b71 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetModule.swift @@ -1,22 +1,19 @@ -import UIKit import MarketKit +import UIKit struct NftAssetModule { - static func viewController(providerCollectionUid: String, nftUid: NftUid) -> UIViewController { let overviewController = NftAssetOverviewModule.viewController(providerCollectionUid: providerCollectionUid, nftUid: nftUid) let activityController = NftActivityModule.viewController(eventListType: .asset(nftUid: nftUid), defaultEventType: nil) return NftAssetViewController( - overviewController: overviewController, - activityController: activityController + overviewController: overviewController, + activityController: activityController ) } - } extension NftAssetModule { - enum Tab: Int, CaseIterable { case overview case activity @@ -28,5 +25,4 @@ extension NftAssetModule { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetTitleCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetTitleCell.swift index 872f96c6b2..70e44be3e9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetTitleCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetTitleCell.swift @@ -1,5 +1,5 @@ -import UIKit import ComponentKit +import UIKit class NftAssetTitleCell: UITableViewCell { private static let horizontalMargin: CGFloat = .margin16 @@ -24,7 +24,8 @@ class NftAssetTitleCell: UITableViewCell { label.textColor = .themeLeah } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -32,14 +33,11 @@ class NftAssetTitleCell: UITableViewCell { get { label.text } set { label.text = newValue } } - } extension NftAssetTitleCell { - static func height(containerWidth: CGFloat, text: String) -> CGFloat { let textWidth = containerWidth - 2 * horizontalMargin return text.height(forContainerWidth: textWidth, font: font) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetViewController.swift index ebff4b07c5..f0096e7e33 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/NftAssetViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import RxSwift -import RxCocoa -import HUD import ComponentKit +import HUD +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class NftAssetViewController: ThemeViewController { private let tabsView = FilterView(buttonStyle: .tab) @@ -22,7 +22,8 @@ class NftAssetViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -83,5 +84,4 @@ class NftAssetViewController: ThemeViewController { case .activity: return activityController } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewModule.swift index 801e20d7eb..c4462dc92b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewModule.swift @@ -1,22 +1,21 @@ import UIKit struct NftAssetOverviewModule { - static func viewController(providerCollectionUid: String, nftUid: NftUid) -> NftAssetOverviewViewController { let coinPriceService = WalletCoinPriceService( - tag: "nft-asset-overview", - currencyManager: App.shared.currencyManager, - marketKit: App.shared.marketKit + tag: "nft-asset-overview", + currencyManager: App.shared.currencyManager, + marketKit: App.shared.marketKit ) let service = NftAssetOverviewService( - providerCollectionUid: providerCollectionUid, - nftUid: nftUid, - accountManager: App.shared.accountManager, - nftAdapterManager: App.shared.nftAdapterManager, - nftMetadataManager: App.shared.nftMetadataManager, - marketKit: App.shared.marketKit, - coinPriceService: coinPriceService + providerCollectionUid: providerCollectionUid, + nftUid: nftUid, + accountManager: App.shared.accountManager, + nftAdapterManager: App.shared.nftAdapterManager, + nftMetadataManager: App.shared.nftMetadataManager, + marketKit: App.shared.marketKit, + coinPriceService: coinPriceService ) coinPriceService.delegate = service @@ -24,7 +23,6 @@ struct NftAssetOverviewModule { let viewModel = NftAssetOverviewViewModel(service: service) return NftAssetOverviewViewController(viewModel: viewModel, urlManager: UrlManager(inApp: true)) } - } enum NftImage { @@ -33,7 +31,7 @@ enum NftImage { var ratio: CGFloat { switch self { - case .image(let image): return image.size.height / image.size.width + case let .image(image): return image.size.height / image.size.width case .svg: return 1 } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewService.swift index d878625b6f..1e3acbd47e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewService.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import MarketKit import Kingfisher +import MarketKit +import RxRelay +import RxSwift class NftAssetOverviewService { let providerCollectionUid: String @@ -53,13 +53,13 @@ class NftAssetOverviewService { state = .loading nftMetadataManager.extendedAssetMetadataSingle(nftUid: nftUid, providerCollectionUid: providerCollectionUid) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] asset, collection in - self?.handleFetched(asset: asset, collection: collection) - }, onError: { [weak self] error in - self?.state = .failed(error) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] asset, collection in + self?.handleFetched(asset: asset, collection: collection) + }, onError: { [weak self] error in + self?.state = .failed(error) + }) + .disposed(by: disposeBag) } private func handleFetched(asset: NftAssetMetadata, collection: NftCollectionMetadata) { @@ -80,7 +80,7 @@ class NftAssetOverviewService { } else { KingfisherManager.shared.retrieveImage(with: url) { [weak self] result in switch result { - case .success(let result): + case let .success(result): self?.handleFetched(asset: asset, collection: collection, nftImage: .image(image: result.image)) case .failure: self?.handleFetched(asset: asset, collection: collection, nftImage: nil) @@ -102,7 +102,7 @@ class NftAssetOverviewService { private func handleUpdatedRecords() { queue.async { - guard case .completed(let item) = self.state else { + guard case let .completed(item) = self.state else { return } @@ -112,7 +112,7 @@ class NftAssetOverviewService { } private func _isOwned() -> Bool { - guard let adapter = adapter else { + guard let adapter else { return false } @@ -123,7 +123,7 @@ class NftAssetOverviewService { var priceItems = [item.lastSale, item.average7d, item.average30d, item.collectionFloor] + item.offers if let saleItem = item.sale { - priceItems.append(contentsOf: saleItem.listings.map { $0.price }) + priceItems.append(contentsOf: saleItem.listings.map(\.price)) } return Set(priceItems.compactMap { $0?.nftPrice.token.coin.uid }) @@ -157,14 +157,12 @@ class NftAssetOverviewService { priceItem?.coinPrice = map[coinUid] } - } extension NftAssetOverviewService: IWalletCoinPriceServiceDelegate { - func didUpdateBaseCurrency() { queue.async { - guard case .completed(let item) = self.state else { + guard case let .completed(item) = self.state else { return } @@ -175,7 +173,7 @@ extension NftAssetOverviewService: IWalletCoinPriceServiceDelegate { func didUpdate(itemsMap: [String: WalletCoinPriceService.Item]) { queue.async { - guard case .completed(let item) = self.state else { + guard case let .completed(item) = self.state else { return } @@ -186,7 +184,6 @@ extension NftAssetOverviewService: IWalletCoinPriceServiceDelegate { } extension NftAssetOverviewService { - var stateObservable: Observable> { stateRelay.asObservable() } @@ -200,11 +197,9 @@ extension NftAssetOverviewService { self.sync() } } - } extension NftAssetOverviewService { - class Item { let asset: NftAssetMetadata let collection: NftCollectionMetadata @@ -231,13 +226,13 @@ extension NftAssetOverviewService { offers = asset.offers.map { PriceItem(nftPrice: $0) } sale = asset.saleInfo.map { saleInfo in SaleItem( - type: saleInfo.type, - listings: saleInfo.listings.map { listing in - SaleListingItem( - untilDate: listing.untilDate, - price: PriceItem(nftPrice: listing.price) - ) - } + type: saleInfo.type, + listings: saleInfo.listings.map { listing in + SaleListingItem( + untilDate: listing.untilDate, + price: PriceItem(nftPrice: listing.price) + ) + } ) } } @@ -313,5 +308,4 @@ extension NftAssetOverviewService { self.coinPrice = coinPrice } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewController.swift index 89e60fad4a..643d8c62f5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import SnapKit -import RxSwift -import RxCocoa -import ThemeKit import ComponentKit -import SectionsTableView import HUD +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class NftAssetOverviewViewController: ThemeViewController { private let viewModel: NftAssetOverviewViewModel @@ -33,7 +33,8 @@ class NftAssetOverviewViewController: ThemeViewController { super.init() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -136,7 +137,7 @@ class NftAssetOverviewViewController: ThemeViewController { private func linkTitle(type: NftAssetOverviewViewModel.LinkType) -> String { switch type { case .website: return "nft_asset.links.website".localized - case .provider(let title): return title + case let .provider(title): return title case .discord: return "Discord" case .twitter: return "Twitter" } @@ -179,7 +180,7 @@ class NftAssetOverviewViewController: ThemeViewController { } private func handleShare() { - if let providerUrl = providerUrl { + if let providerUrl { openShare(text: providerUrl) } } @@ -195,7 +196,7 @@ class NftAssetOverviewViewController: ThemeViewController { } private var providerUrl: String? { - guard let viewItem = viewItem else { + guard let viewItem else { return nil } @@ -209,7 +210,7 @@ class NftAssetOverviewViewController: ThemeViewController { return nil } - @objc private func onSaveToPhotos(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { + @objc private func onSaveToPhotos(_: UIImage, didFinishSavingWithError error: Error?, contextInfo _: UnsafeRawPointer) { if error == nil { HudHelper.instance.show(banner: .saved) } else { @@ -222,118 +223,116 @@ class NftAssetOverviewViewController: ThemeViewController { (parentNavigationController ?? navigationController)?.pushViewController(module, animated: true) } } - } extension NftAssetOverviewViewController: SectionsDataSource { - private func headerRow(title: String) -> RowProtocol { tableView.headerInfoRow(id: "header-\(title)", title: title) } private func imageSection(ratio: CGFloat) -> SectionProtocol { Section( - id: "image", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: imageCell, - id: "image", - dynamicHeight: { width in - NftAssetImageCell.height(containerWidth: width, ratio: ratio) - } - ) - ] + id: "image", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: imageCell, + id: "image", + dynamicHeight: { width in + NftAssetImageCell.height(containerWidth: width, ratio: ratio) + } + ), + ] ) } private func titleSection(assetName: String, collectionName: String, providerCollectionUid: String) -> SectionProtocol { Section( - id: "title", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin12), - rows: [ - Row( - id: "title", - dynamicHeight: { width in - NftAssetTitleCell.height(containerWidth: width, text: assetName) - }, - bind: { cell, _ in - cell.text = assetName - } - ), - tableView.universalRow48( - id: "collection", - title: .body(collectionName, color: .themeJacob), - accessoryType: .disclosure, - backgroundStyle: .transparent, - autoDeselect: true, - isFirst: true, - action: { [weak self] in - self?.openCollection(providerUid: providerCollectionUid) - } - ) - ] + id: "title", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin12), + rows: [ + Row( + id: "title", + dynamicHeight: { width in + NftAssetTitleCell.height(containerWidth: width, text: assetName) + }, + bind: { cell, _ in + cell.text = assetName + } + ), + tableView.universalRow48( + id: "collection", + title: .body(collectionName, color: .themeJacob), + accessoryType: .disclosure, + backgroundStyle: .transparent, + autoDeselect: true, + isFirst: true, + action: { [weak self] in + self?.openCollection(providerUid: providerCollectionUid) + } + ), + ] ) } - private func buttonsSection(sendVisible: Bool) -> SectionProtocol { + private func buttonsSection(sendVisible _: Bool) -> SectionProtocol { Section( - id: "buttons", - footerState: .margin(height: .margin24), - rows: [ - Row( - id: "buttons", - height: .heightButton, - bind: { [weak self] cell, _ in - cell.bind( - onTapShare: { [weak self] in - self?.handleShare() - }, - onTapSave: { [weak self] in - self?.handleSaveToPhotos() - } - ) + id: "buttons", + footerState: .margin(height: .margin24), + rows: [ + Row( + id: "buttons", + height: .heightButton, + bind: { [weak self] cell, _ in + cell.bind( + onTapShare: { [weak self] in + self?.handleShare() + }, + onTapSave: { [weak self] in + self?.handleSaveToPhotos() } - ) - ] + ) + } + ), + ] ) } private func priceRow(title: String, viewItem: NftAssetOverviewViewModel.PriceViewItem, isFirst: Bool, isLast: Bool) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ + rootElement: .hStack([ + .text { (component: TextComponent) in + component.font = .body + component.textColor = .themeLeah + component.text = title + }, + .vStackCentered([ .text { (component: TextComponent) in component.font = .body - component.textColor = .themeLeah - component.text = title + component.textColor = .themeJacob + component.text = viewItem.coinValue + component.textAlignment = .right + component.setContentCompressionResistancePriority(.required, for: .horizontal) + }, + .margin(1), + .text { (component: TextComponent) in + component.font = .subhead2 + component.textColor = .themeGray + component.text = viewItem.fiatValue + component.textAlignment = .right + component.setContentCompressionResistancePriority(.required, for: .horizontal) }, - .vStackCentered([ - .text { (component: TextComponent) in - component.font = .body - component.textColor = .themeJacob - component.text = viewItem.coinValue - component.textAlignment = .right - component.setContentCompressionResistancePriority(.required, for: .horizontal) - }, - .margin(1), - .text { (component: TextComponent) in - component.font = .subhead2 - component.textColor = .themeGray - component.text = viewItem.fiatValue - component.textAlignment = .right - component.setContentCompressionResistancePriority(.required, for: .horizontal) - } - ]) ]), - tableView: tableView, - id: "price-\(title)", - hash: "\(viewItem.coinValue)-\(viewItem.fiatValue)-\(isLast)", - height: .heightDoubleLineCell, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) - } + ]), + tableView: tableView, + id: "price-\(title)", + hash: "\(viewItem.coinValue)-\(viewItem.fiatValue)-\(isLast)", + height: .heightDoubleLineCell, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) + } ) } @@ -358,41 +357,41 @@ extension NftAssetOverviewViewController: SectionsDataSource { } return Section( - id: "stats", - footerState: .margin(height: viewItem.sale == nil && viewItem.bestOffer == nil ? .margin24 : .margin12), - rows: rows.enumerated().map { index, rowInfo in - priceRow( - title: rowInfo.0, - viewItem: rowInfo.1, - isFirst: index == 0, - isLast: index == rows.count - 1 - ) - } + id: "stats", + footerState: .margin(height: viewItem.sale == nil && viewItem.bestOffer == nil ? .margin24 : .margin12), + rows: rows.enumerated().map { index, rowInfo in + priceRow( + title: rowInfo.0, + viewItem: rowInfo.1, + isFirst: index == 0, + isLast: index == rows.count - 1 + ) + } ) } private func saleRow(title: String, untilDate: String) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .text { (component: TextComponent) -> () in - component.font = .body - component.textColor = .themeLeah - component.text = title - }, - .margin(1), - .text { (component: TextComponent) -> () in - component.font = .subhead2 - component.textColor = .themeGray - component.text = untilDate - } - ]), - tableView: tableView, - id: "sale-until", - hash: untilDate, - height: .heightDoubleLineCell, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: true) - } + rootElement: .hStack([ + .text { (component: TextComponent) in + component.font = .body + component.textColor = .themeLeah + component.text = title + }, + .margin(1), + .text { (component: TextComponent) in + component.font = .subhead2 + component.textColor = .themeGray + component.text = untilDate + }, + ]), + tableView: tableView, + id: "sale-until", + hash: untilDate, + height: .heightDoubleLineCell, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: true) + } ) } @@ -402,20 +401,20 @@ extension NftAssetOverviewViewController: SectionsDataSource { } return Section( - id: "sale", - footerState: .margin(height: viewItem.bestOffer == nil ? .margin24 : .margin12), - rows: [ - saleRow( - title: saleTitle(type: saleViewItem.type), - untilDate: saleViewItem.untilDate - ), - priceRow( - title: salePriceTitle(type: saleViewItem.type), - viewItem: saleViewItem.price, - isFirst: false, - isLast: true - ) - ] + id: "sale", + footerState: .margin(height: viewItem.bestOffer == nil ? .margin24 : .margin12), + rows: [ + saleRow( + title: saleTitle(type: saleViewItem.type), + untilDate: saleViewItem.untilDate + ), + priceRow( + title: salePriceTitle(type: saleViewItem.type), + viewItem: saleViewItem.price, + isFirst: false, + isLast: true + ), + ] ) } @@ -425,16 +424,16 @@ extension NftAssetOverviewViewController: SectionsDataSource { } return Section( - id: "best-offer", - footerState: .margin(height: .margin24), - rows: [ - priceRow( - title: "nft_asset.best_offer".localized, - viewItem: priceViewItem, - isFirst: true, - isLast: true - ) - ] + id: "best-offer", + footerState: .margin(height: .margin24), + rows: [ + priceRow( + title: "nft_asset.best_offer".localized, + viewItem: priceViewItem, + isFirst: true, + isLast: true + ), + ] ) } @@ -472,27 +471,27 @@ extension NftAssetOverviewViewController: SectionsDataSource { return [ Section( - id: "traits-header", - rows: [ - headerRow(title: "nft_asset.properties".localized) - ] + id: "traits-header", + rows: [ + headerRow(title: "nft_asset.properties".localized), + ] ), Section( - id: "traits", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin24), - rows: [ - Row( - id: "traits", - height: TraitsCell.height(lines: lines), - bind: { [weak self] cell, _ in - cell.bind(viewItems: sortedTraits, onSelect: { index in - self?.viewModel.onSelectTrait(index: index) - }) - } - ) - ] - ) + id: "traits", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin24), + rows: [ + Row( + id: "traits", + height: TraitsCell.height(lines: lines), + bind: { [weak self] cell, _ in + cell.bind(viewItems: sortedTraits, onSelect: { index in + self?.viewModel.onSelectTrait(index: index) + }) + } + ), + ] + ), ] } @@ -500,66 +499,66 @@ extension NftAssetOverviewViewController: SectionsDataSource { descriptionTextCell.contentText = NSAttributedString(string: description, attributes: [.font: UIFont.subhead2, .foregroundColor: UIColor.themeGray]) let descriptionRow = StaticRow( - cell: descriptionTextCell, - id: "description", - dynamicHeight: { [weak self] containerWidth in - self?.descriptionTextCell.cellHeight(containerWidth: containerWidth) ?? 0 - } + cell: descriptionTextCell, + id: "description", + dynamicHeight: { [weak self] containerWidth in + self?.descriptionTextCell.cellHeight(containerWidth: containerWidth) ?? 0 + } ) return Section( - id: "description", - footerState: .margin(height: .margin24), - rows: [ - headerRow(title: "nft_asset.description".localized), - descriptionRow - ] + id: "description", + footerState: .margin(height: .margin24), + rows: [ + headerRow(title: "nft_asset.description".localized), + descriptionRow, + ] ) } private func contractAddressRow(value: String) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .text { (component: TextComponent) -> () in - component.font = .body - component.textColor = .themeLeah - component.text = "nft_asset.details.contract_address".localized - }, - .secondaryCircleButton { (component: SecondaryCircleButtonComponent) -> () in - component.button.set(image: UIImage(named: "copy_20")) - component.onTap = { - CopyHelper.copyAndNotify(value: value) - } - }, - .secondaryCircleButton { [weak self] (component: SecondaryCircleButtonComponent) -> () in - component.button.set(image: UIImage(named: "share_1_20")) - component.onTap = { - self?.openShare(text: value) - } - }, - ]), - tableView: tableView, - id: "contract-address", - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: true) - } + rootElement: .hStack([ + .text { (component: TextComponent) in + component.font = .body + component.textColor = .themeLeah + component.text = "nft_asset.details.contract_address".localized + }, + .secondaryCircleButton { (component: SecondaryCircleButtonComponent) in + component.button.set(image: UIImage(named: "copy_20")) + component.onTap = { + CopyHelper.copyAndNotify(value: value) + } + }, + .secondaryCircleButton { [weak self] (component: SecondaryCircleButtonComponent) in + component.button.set(image: UIImage(named: "share_1_20")) + component.onTap = { + self?.openShare(text: value) + } + }, + ]), + tableView: tableView, + id: "contract-address", + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: true) + } ) } private func detailRow(title: String, value: String, isLast: Bool = false) -> RowProtocol { tableView.universalRow48( - id: "detail-\(title)", - title: .body(title), - value: .subhead1(value, color: .themeGray), - isLast: isLast + id: "detail-\(title)", + title: .body(title), + value: .subhead1(value, color: .themeGray), + isLast: isLast ) } private func detailsSections(viewItem: NftAssetOverviewViewModel.ViewItem) -> [SectionProtocol] { var rows: [RowProtocol] = [ contractAddressRow(value: viewItem.contractAddress), - detailRow(title: "nft_asset.details.token_id".localized, value: viewItem.tokenId) + detailRow(title: "nft_asset.details.token_id".localized, value: viewItem.tokenId), ] if let schemaName = viewItem.schemaName { @@ -570,81 +569,82 @@ extension NftAssetOverviewViewController: SectionsDataSource { return [ Section( - id: "details-header", - rows: [ - headerRow(title: "nft_asset.details".localized) - ] + id: "details-header", + rows: [ + headerRow(title: "nft_asset.details".localized), + ] ), Section( - id: "details", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin24), - rows: rows - ) + id: "details", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin24), + rows: rows + ), ] } private func linkRow(iconImage: UIImage?, title: String, url: String, isFirst: Bool, isLast: Bool) -> RowProtocol { tableView.universalRow48( - id: "link-\(title)", - image: .local(iconImage?.withTintColor(.themeGray)), - title: .body(title), - accessoryType: .disclosure, - autoDeselect: true, - isFirst: isFirst, - isLast: isLast, - action: { [weak self] in - self?.openLink(url: url) - }) + id: "link-\(title)", + image: .local(iconImage?.withTintColor(.themeGray)), + title: .body(title), + accessoryType: .disclosure, + autoDeselect: true, + isFirst: isFirst, + isLast: isLast, + action: { [weak self] in + self?.openLink(url: url) + } + ) } private func linksSections(links: [NftAssetOverviewViewModel.LinkViewItem]) -> [SectionProtocol] { [ Section( - id: "links-header", - rows: [ - headerRow(title: "nft_asset.links".localized) - ] + id: "links-header", + rows: [ + headerRow(title: "nft_asset.links".localized), + ] ), Section( - id: "links", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin24), - rows: links.enumerated().map { index, link in - linkRow( - iconImage: linkIcon(type: link.type), - title: linkTitle(type: link.type), - url: link.url, - isFirst: index == 0, - isLast: index == links.count - 1 - ) - } - ) + id: "links", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin24), + rows: links.enumerated().map { index, link in + linkRow( + iconImage: linkIcon(type: link.type), + title: linkTitle(type: link.type), + url: link.url, + isFirst: index == 0, + isLast: index == links.count - 1 + ) + } + ), ] } private func poweredBySection(text: String) -> SectionProtocol { Section( - id: "powered-by", - headerState: .margin(height: .margin8), - rows: [ - Row( - id: "powered-by", - dynamicHeight: { containerWidth in - BrandFooterCell.height(containerWidth: containerWidth, title: text) - }, - bind: { cell, _ in - cell.title = text - } - ) - ] + id: "powered-by", + headerState: .margin(height: .margin8), + rows: [ + Row( + id: "powered-by", + dynamicHeight: { containerWidth in + BrandFooterCell.height(containerWidth: containerWidth, title: text) + }, + bind: { cell, _ in + cell.title = text + } + ), + ] ) } func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let viewItem = viewItem { + if let viewItem { if let nftImage = viewItem.nftImage { imageCell.bind(nftImage: nftImage) sections.append(imageSection(ratio: nftImage.ratio)) @@ -684,5 +684,4 @@ extension NftAssetOverviewViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewModel.swift index 676b5a5355..6254f4bbce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/Overview/NftAssetOverviewViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class NftAssetOverviewViewModel { private let service: NftAssetOverviewService @@ -28,7 +28,7 @@ class NftAssetOverviewViewModel { viewItemRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .completed(let item): + case let .completed(item): viewItemRelay.accept(viewItem(item: item)) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -44,50 +44,50 @@ class NftAssetOverviewViewModel { let collection = item.collection return ViewItem( - nftImage: item.assetNftImage, - name: asset.name ?? "#\(service.nftUid.tokenId)", - providerCollectionUid: asset.providerCollectionUid, - collectionName: collection.name, - lastSale: priceViewItem(priceItem: item.lastSale), - average7d: priceViewItem(priceItem: item.average7d), - average30d: priceViewItem(priceItem: item.average30d), - collectionFloor: priceViewItem(priceItem: item.collectionFloor), - bestOffer: priceViewItem(priceItem: item.bestOffer), - sale: saleViewItem(saleItem: item.sale), - traits: asset.traits.enumerated().map { traitViewItem(index: $0, trait: $1, totalSupply: collection.totalSupply) }, - description: asset.description, - contractAddress: service.nftUid.contractAddress, - tokenId: service.nftUid.tokenId, - schemaName: asset.contract.schema, - blockchain: service.nftUid.blockchainType.uid, - links: linkViewItems(asset: asset, collection: collection), - sendVisible: item.isOwned + nftImage: item.assetNftImage, + name: asset.name ?? "#\(service.nftUid.tokenId)", + providerCollectionUid: asset.providerCollectionUid, + collectionName: collection.name, + lastSale: priceViewItem(priceItem: item.lastSale), + average7d: priceViewItem(priceItem: item.average7d), + average30d: priceViewItem(priceItem: item.average30d), + collectionFloor: priceViewItem(priceItem: item.collectionFloor), + bestOffer: priceViewItem(priceItem: item.bestOffer), + sale: saleViewItem(saleItem: item.sale), + traits: asset.traits.enumerated().map { traitViewItem(index: $0, trait: $1, totalSupply: collection.totalSupply) }, + description: asset.description, + contractAddress: service.nftUid.contractAddress, + tokenId: service.nftUid.tokenId, + schemaName: asset.contract.schema, + blockchain: service.nftUid.blockchainType.uid, + links: linkViewItems(asset: asset, collection: collection), + sendVisible: item.isOwned ) } private func saleViewItem(saleItem: NftAssetOverviewService.SaleItem?) -> SaleViewItem? { - guard let saleItem = saleItem, let listing = saleItem.bestListing else { + guard let saleItem, let listing = saleItem.bestListing else { return nil } return SaleViewItem( - untilDate: "nft_asset.until_date".localized(DateHelper.instance.formatFullTime(from: listing.untilDate)), - type: saleItem.type, - price: PriceViewItem( - coinValue: coinValue(priceItem: listing.price), - fiatValue: fiatValue(priceItem: listing.price) - ) + untilDate: "nft_asset.until_date".localized(DateHelper.instance.formatFullTime(from: listing.untilDate)), + type: saleItem.type, + price: PriceViewItem( + coinValue: coinValue(priceItem: listing.price), + fiatValue: fiatValue(priceItem: listing.price) + ) ) } private func priceViewItem(priceItem: NftAssetOverviewService.PriceItem?) -> PriceViewItem? { - guard let priceItem = priceItem else { + guard let priceItem else { return nil } return PriceViewItem( - coinValue: coinValue(priceItem: priceItem), - fiatValue: fiatValue(priceItem: priceItem) + coinValue: coinValue(priceItem: priceItem), + fiatValue: fiatValue(priceItem: priceItem) ) } @@ -108,7 +108,7 @@ class NftAssetOverviewViewModel { private func traitViewItem(index: Int, trait: NftAssetMetadata.Trait, totalSupply: Int?) -> TraitViewItem { var percentString: String? - if let totalSupply = totalSupply, trait.count != 0, totalSupply != 0 { + if let totalSupply, trait.count != 0, totalSupply != 0 { let percent = Double(trait.count) * 100.0 / Double(totalSupply) let rounded: Double @@ -124,10 +124,10 @@ class NftAssetOverviewViewModel { } return TraitViewItem( - index: index, - type: trait.type.capitalized, - value: trait.value.capitalized, - percent: percentString.map { "\($0)%" } + index: index, + type: trait.type.capitalized, + value: trait.value.capitalized, + percent: percentString.map { "\($0)%" } ) } @@ -149,7 +149,6 @@ class NftAssetOverviewViewModel { return viewItems } - } extension NftAssetOverviewViewModel { @@ -186,7 +185,7 @@ extension NftAssetOverviewViewModel { } func onSelectTrait(index: Int) { - guard case .completed(let item) = service.state else { + guard case let .completed(item) = service.state else { return } @@ -205,16 +204,14 @@ extension NftAssetOverviewViewModel { } let url = providerTraitLink - .replacingOccurrences(of: "$traitName", with: traitName) - .replacingOccurrences(of: "$traitValue", with: traitValue) + .replacingOccurrences(of: "$traitName", with: traitName) + .replacingOccurrences(of: "$traitValue", with: traitValue) openTraitRelay.accept(url) } - } extension NftAssetOverviewViewModel { - struct ViewItem { let nftImage: NftImage? let name: String @@ -265,5 +262,4 @@ extension NftAssetOverviewViewModel { case discord case twitter } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitCell.swift index 832d186a59..0d7c4be74f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import ComponentKit +import ThemeKit +import UIKit class TraitCell: UICollectionViewCell { private static let horizontalPadding: CGFloat = .margin16 @@ -52,7 +52,8 @@ class TraitCell: UICollectionViewCell { typeLabel.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -86,5 +87,4 @@ class TraitCell: UICollectionViewCell { contentView.backgroundColor = newValue ? .themeLawrencePressed : .themeLawrence } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitsCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitsCell.swift index 53f33a98b2..119353dfdf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitsCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftAsset/TraitsCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import ComponentKit import AlignedCollectionViewFlowLayout +import ComponentKit +import ThemeKit +import UIKit class TraitsCell: UITableViewCell { private static let lineSpacing: CGFloat = .margin6 @@ -12,7 +12,7 @@ class TraitsCell: UITableViewCell { private let collectionView: UICollectionView private var viewItems: [NftAssetOverviewViewModel.TraitViewItem] = [] - private var onSelect: ((Int) -> ())? + private var onSelect: ((Int) -> Void)? override init(style: CellStyle, reuseIdentifier: String?) { layout.scrollDirection = .vertical @@ -41,11 +41,12 @@ class TraitsCell: UITableViewCell { collectionView.registerCell(forClass: TraitCell.self) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - func bind(viewItems: [NftAssetOverviewViewModel.TraitViewItem], onSelect: @escaping (Int) -> ()) { + func bind(viewItems: [NftAssetOverviewViewModel.TraitViewItem], onSelect: @escaping (Int) -> Void) { self.viewItems = viewItems self.onSelect = onSelect @@ -55,12 +56,10 @@ class TraitsCell: UITableViewCell { static func height(lines: Int) -> CGFloat { CGFloat(lines) * TraitCell.height + CGFloat(lines - 1) * lineSpacing } - } extension TraitsCell: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { viewItems.count } @@ -68,21 +67,21 @@ extension TraitsCell: UICollectionViewDelegateFlowLayout, UICollectionViewDataSo collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: TraitCell.self), for: indexPath) } - func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? TraitCell { cell.bind(viewItem: viewItems[indexPath.item]) } } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { TraitCell.size(for: viewItems[indexPath.item], containerWidth: collectionView.bounds.width - CGFloat.margin16 * 2) } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { Self.interItemSpacing } - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, didSelectItemAt indexPath: IndexPath) { guard indexPath.item < viewItems.count else { return } @@ -90,5 +89,4 @@ extension TraitsCell: UICollectionViewDelegateFlowLayout, UICollectionViewDataSo let viewItem = viewItems[indexPath.item] onSelect?(viewItem.index) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityHeaderView.swift index fae7365634..ee5db7f011 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityHeaderView.swift @@ -1,9 +1,9 @@ -import UIKit -import SnapKit +import ComponentKit import RxSwift -import UIExtensions +import SnapKit import ThemeKit -import ComponentKit +import UIExtensions +import UIKit class NftActivityHeaderView: UIView { private let viewModel: NftActivityViewModel @@ -49,14 +49,15 @@ class NftActivityHeaderView: UIView { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func onTapEventType() { let alertController = AlertRouter.module( - title: "nft.activity.event_types".localized, - viewItems: viewModel.eventTypeViewItems + title: "nft.activity.event_types".localized, + viewItems: viewModel.eventTypeViewItems ) { [weak self] index in self?.viewModel.onSelectEventType(index: index) } @@ -66,15 +67,14 @@ class NftActivityHeaderView: UIView { @objc private func onTapContract() { let viewController = SelectorModule.bottomSingleSelectorViewController( - image: .local(name: "paper_contract_24", tint: .warning), - title: "nft.activity.contracts".localized, - viewItems: viewModel.contractViewItems, - onSelect: { [weak self] index in - self?.viewModel.onSelectContract(index: index) - } + image: .local(name: "paper_contract_24", tint: .warning), + title: "nft.activity.contracts".localized, + viewItems: viewModel.contractViewItems, + onSelect: { [weak self] index in + self?.viewModel.onSelectContract(index: index) + } ) self.viewController?.present(viewController, animated: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityModule.swift index 24458c8784..9af6c0ba4c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityModule.swift @@ -1,9 +1,8 @@ -import UIKit -import SectionsTableView import MarketKit +import SectionsTableView +import UIKit struct NftActivityModule { - static func viewController(eventListType: NftEventListType, defaultEventType: NftEventMetadata.EventType? = .sale) -> NftActivityViewController { let coinPriceService = WalletCoinPriceService(tag: "nft-activity", currencyManager: App.shared.currencyManager, marketKit: App.shared.marketKit) let service = NftActivityService(eventListType: eventListType, defaultEventType: defaultEventType, nftMetadataManager: App.shared.nftMetadataManager, coinPriceService: coinPriceService) @@ -11,7 +10,7 @@ struct NftActivityModule { let cellFactory: INftActivityCellFactory switch eventListType { - case .collection(_, let providerUid): cellFactory = NftCollectionCellFactory(providerCollectionUid: providerUid) + case let .collection(_, providerUid): cellFactory = NftCollectionCellFactory(providerCollectionUid: providerUid) case .asset: cellFactory = NftAssetCellFactory() } @@ -22,10 +21,9 @@ struct NftActivityModule { case collection(blockchainType: BlockchainType, providerUid: String) case asset(nftUid: NftUid) } - } protocol INftActivityCellFactory: AnyObject { var parentNavigationController: UINavigationController? { get set } - func row(tableView: UITableView, viewItem: NftActivityViewModel.EventViewItem, index: Int, onReachBottom: (() -> ())?) -> RowProtocol + func row(tableView: UITableView, viewItem: NftActivityViewModel.EventViewItem, index: Int, onReachBottom: (() -> Void)?) -> RowProtocol } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityService.swift index 7d99382f88..72f81da1d7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class NftActivityService { private let eventListType: NftActivityModule.NftEventListType @@ -83,31 +83,31 @@ class NftActivityService { case let .collection(blockchainType, providerUid): if contracts.isEmpty { nftMetadataManager.collectionMetadataSingle(blockchainType: blockchainType, providerUid: providerUid) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] collection in - if collection.contracts.isEmpty { - self?.handle(error: FetchError.noContract) - } else { - self?.contracts = collection.contracts - self?.loadInitial() - } - }, onError: { [weak self] error in - self?.handle(error: error) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] collection in + if collection.contracts.isEmpty { + self?.handle(error: FetchError.noContract) + } else { + self?.contracts = collection.contracts + self?.loadInitial() + } + }, onError: { [weak self] error in + self?.handle(error: error) + }) + .disposed(by: disposeBag) return } default: () } single() - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] events, paginationData in - self?.handle(events: events, paginationData: paginationData) - }, onError: { [weak self] error in - self?.handle(error: error) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] events, paginationData in + self?.handle(events: events, paginationData: paginationData) + }, onError: { [weak self] error in + self?.handle(error: error) + }) + .disposed(by: disposeBag) } private func _loadMore() { @@ -122,14 +122,14 @@ class NftActivityService { loadingMore = true single(paginationData: paginationData) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] events, paginationData in - self?.handleMore(events: events, paginationData: paginationData) - self?.loadingMore = false - }, onError: { [weak self] error in - self?.loadingMore = false - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] events, paginationData in + self?.handleMore(events: events, paginationData: paginationData) + self?.loadingMore = false + }, onError: { [weak self] _ in + self?.loadingMore = false + }) + .disposed(by: disposeBag) } private func handle(events: [NftEventMetadata], paginationData: PaginationData?) { @@ -141,7 +141,7 @@ class NftActivityService { private func handleMore(events: [NftEventMetadata], paginationData: PaginationData?) { queue.async { - guard case .loaded(let items, _) = self.state else { + guard case let .loaded(items, _) = self.state else { return } @@ -183,14 +183,12 @@ class NftActivityService { item.priceItem = item.event.price.flatMap { map[$0.token.coin.uid] } } } - } extension NftActivityService: IWalletCoinPriceServiceDelegate { - func didUpdateBaseCurrency() { queue.async { - guard case .loaded(let items, let allLoaded) = self.state else { + guard case let .loaded(items, allLoaded) = self.state else { return } @@ -201,7 +199,7 @@ extension NftActivityService: IWalletCoinPriceServiceDelegate { func didUpdate(itemsMap: [String: WalletCoinPriceService.Item]) { queue.async { - guard case .loaded(let items, let allLoaded) = self.state else { + guard case let .loaded(items, allLoaded) = self.state else { return } @@ -209,11 +207,9 @@ extension NftActivityService: IWalletCoinPriceServiceDelegate { self.state = .loaded(items: items, allLoaded: allLoaded) } } - } extension NftActivityService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -232,7 +228,7 @@ extension NftActivityService { var blockchainType: BlockchainType? { switch eventListType { - case .collection(let blockchainType, _): return blockchainType + case let .collection(blockchainType, _): return blockchainType default: return nil } } @@ -254,11 +250,9 @@ extension NftActivityService { self._loadMore() } } - } extension NftActivityService { - enum State { case loading case loaded(items: [Item], allLoaded: Bool) @@ -277,5 +271,4 @@ extension NftActivityService { enum FetchError: Error { case noContract } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewController.swift index 1ed455a5ad..0a2b5feee1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import SnapKit -import RxSwift -import RxCocoa -import ThemeKit import ComponentKit -import SectionsTableView import HUD +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class NftActivityViewController: ThemeViewController { private let viewModel: NftActivityViewModel @@ -37,7 +37,8 @@ class NftActivityViewController: ThemeViewController { headerView.viewController = self } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -119,19 +120,17 @@ class NftActivityViewController: ThemeViewController { spinnerWrapper.isHidden = viewItem != nil emptyView.isHidden = !(viewItem.map { $0.eventViewItems.isEmpty && $0.allLoaded } ?? false) } - } extension NftActivityViewController: SectionsDataSource { - private func row(eventViewItem viewItem: NftActivityViewModel.EventViewItem, index: Int, isLast: Bool) -> RowProtocol { cellFactory.row(tableView: tableView, viewItem: viewItem, index: index, onReachBottom: isLast ? { [weak self] in self?.viewModel.onReachBottom() } : nil) } private func spinnerRow() -> RowProtocol { Row( - id: "spinner", - height: 24 + id: "spinner", + height: 24 ) } @@ -139,27 +138,27 @@ extension NftActivityViewController: SectionsDataSource { var sections = [SectionProtocol]() var rows = [RowProtocol]() - if let viewItem = viewItem { + if let viewItem { rows = viewItem.eventViewItems.enumerated().map { index, eventViewItem in row(eventViewItem: eventViewItem, index: index, isLast: index == viewItem.eventViewItems.count - 1) } } let mainSection = Section( - id: "main", - footerState: .marginColor(height: .margin12, color: .clear), - rows: rows + id: "main", + footerState: .marginColor(height: .margin12, color: .clear), + rows: rows ) sections.append(mainSection) - if let viewItem = viewItem, !viewItem.allLoaded { + if let viewItem, !viewItem.allLoaded { let spinnerSection = Section( - id: "spinner", - footerState: .marginColor(height: .margin32, color: .clear), - rows: [ - spinnerRow() - ] + id: "spinner", + footerState: .marginColor(height: .margin32, color: .clear), + rows: [ + spinnerRow(), + ] ) sections.append(spinnerSection) @@ -167,5 +166,4 @@ extension NftActivityViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewModel.swift index 9436f27ea7..1b2102f8fb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftActivityViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class NftActivityViewModel { private let service: NftActivityService @@ -44,10 +44,10 @@ class NftActivityViewModel { viewItemRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .loaded(let items, let allLoaded): + case let .loaded(items, allLoaded): let viewItem = ViewItem( - eventViewItems: items.map { eventViewItem(item: $0) }, - allLoaded: allLoaded + eventViewItems: items.map { eventViewItem(item: $0) }, + allLoaded: allLoaded ) viewItemRelay.accept(viewItem) @@ -86,27 +86,25 @@ class NftActivityViewModel { } return EventViewItem( - nftUid: event.nftUid, - type: type, - date: DateHelper.instance.formatFullTime(from: event.date), - imageUrl: event.previewImageUrl, - coinPrice: coinPrice, - fiatPrice: fiatPrice + nftUid: event.nftUid, + type: type, + date: DateHelper.instance.formatFullTime(from: event.date), + imageUrl: event.previewImageUrl, + coinPrice: coinPrice, + fiatPrice: fiatPrice ) } private func title(eventType: NftEventMetadata.EventType?) -> String { - guard let eventType = eventType else { + guard let eventType else { return "nft.activity.event_type.all".localized } return "nft.activity.event_type.\(eventType)".localized } - } extension NftActivityViewModel { - var eventTypeDriver: Driver { eventTypeRelay.asDriver() } @@ -134,11 +132,11 @@ extension NftActivityViewModel { return service.contracts.enumerated().map { index, contract in SelectorModule.ViewItem( - image: .url(blockchainType.imageUrl, placeholder: "placeholder_rectangle_32"), - title: contract.name, - subtitle: contract.address.shortened, - badge: contract.schema, - selected: service.contractIndex == index + image: .url(blockchainType.imageUrl, placeholder: "placeholder_rectangle_32"), + title: contract.name, + subtitle: contract.address.shortened, + badge: contract.schema, + selected: service.contractIndex == index ) } } @@ -178,11 +176,9 @@ extension NftActivityViewModel { func onReachBottom() { service.loadMore() } - } extension NftActivityViewModel { - struct ViewItem { let eventViewItems: [EventViewItem] let allLoaded: Bool @@ -196,5 +192,4 @@ extension NftActivityViewModel { let coinPrice: String let fiatPrice: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftCollectionCellFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftCollectionCellFactory.swift index 4a7dd782a4..cc52257193 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftCollectionCellFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Activity/NftCollectionCellFactory.swift @@ -1,6 +1,6 @@ -import UIKit -import SectionsTableView import ComponentKit +import SectionsTableView +import UIKit class NftCollectionCellFactory: NftAssetCellFactory { private let providerCollectionUid: String @@ -9,7 +9,7 @@ class NftCollectionCellFactory: NftAssetCellFactory { self.providerCollectionUid = providerCollectionUid } - override func action(viewItem: NftActivityViewModel.EventViewItem) -> (() -> ())? { + override func action(viewItem: NftActivityViewModel.EventViewItem) -> (() -> Void)? { guard let nftUid = viewItem.nftUid else { return nil } @@ -22,7 +22,7 @@ class NftCollectionCellFactory: NftAssetCellFactory { override func cellElement(viewItem: NftActivityViewModel.EventViewItem) -> CellBuilderNew.CellElement { .hStack([ image(viewItem: viewItem), - super.cellElement(viewItem: viewItem) + super.cellElement(viewItem: viewItem), ]) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsModule.swift index eee6168504..8223a2daf8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsModule.swift @@ -1,12 +1,10 @@ import MarketKit struct NftCollectionAssetsModule { - static func viewController(blockchainType: BlockchainType, providerCollectionUid: String) -> NftCollectionAssetsViewController { let coinPriceService = WalletCoinPriceService(tag: "nft-collection-assets", currencyManager: App.shared.currencyManager, marketKit: App.shared.marketKit) let service = NftCollectionAssetsService(blockchainType: blockchainType, providerCollectionUid: providerCollectionUid, nftMetadataManager: App.shared.nftMetadataManager, coinPriceService: coinPriceService) let viewModel = NftCollectionAssetsViewModel(service: service) return NftCollectionAssetsViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsService.swift index 88db168c1c..89e1e4de25 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class NftCollectionAssetsService { private let blockchainType: BlockchainType @@ -35,13 +35,13 @@ class NftCollectionAssetsService { state = .loading nftMetadataManager.collectionAssetsMetadataSingle(blockchainType: blockchainType, providerCollectionUid: providerCollectionUid) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] (assets, paginationData) in - self?.handle(assets: assets, paginationData: paginationData) - }, onError: { [weak self] error in - self?.handle(error: error) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] assets, paginationData in + self?.handle(assets: assets, paginationData: paginationData) + }, onError: { [weak self] error in + self?.handle(error: error) + }) + .disposed(by: disposeBag) } private func _loadMore() { @@ -56,14 +56,14 @@ class NftCollectionAssetsService { loadingMore = true nftMetadataManager.collectionAssetsMetadataSingle(blockchainType: blockchainType, providerCollectionUid: providerCollectionUid, paginationData: paginationData) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] (assets, paginationData) in - self?.handleMore(assets: assets, paginationData: paginationData) - self?.loadingMore = false - }, onError: { [weak self] error in - self?.loadingMore = false - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] assets, paginationData in + self?.handleMore(assets: assets, paginationData: paginationData) + self?.loadingMore = false + }, onError: { [weak self] _ in + self?.loadingMore = false + }) + .disposed(by: disposeBag) } private func handle(assets: [NftAssetMetadata], paginationData: PaginationData?) { @@ -75,7 +75,7 @@ class NftCollectionAssetsService { private func handleMore(assets: [NftAssetMetadata], paginationData: PaginationData?) { queue.async { - guard case .loaded(let items, _) = self.state else { + guard case let .loaded(items, _) = self.state else { return } @@ -117,14 +117,12 @@ class NftCollectionAssetsService { item.priceItem = item.price.flatMap { map[$0.token.coin.uid] } } } - } extension NftCollectionAssetsService: IWalletCoinPriceServiceDelegate { - func didUpdateBaseCurrency() { queue.async { - guard case .loaded(let items, let allLoaded) = self.state else { + guard case let .loaded(items, allLoaded) = self.state else { return } @@ -135,7 +133,7 @@ extension NftCollectionAssetsService: IWalletCoinPriceServiceDelegate { func didUpdate(itemsMap: [String: WalletCoinPriceService.Item]) { queue.async { - guard case .loaded(let items, let allLoaded) = self.state else { + guard case let .loaded(items, allLoaded) = self.state else { return } @@ -143,11 +141,9 @@ extension NftCollectionAssetsService: IWalletCoinPriceServiceDelegate { self.state = .loaded(items: items, allLoaded: allLoaded) } } - } extension NftCollectionAssetsService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -169,11 +165,9 @@ extension NftCollectionAssetsService { self._loadMore() } } - } extension NftCollectionAssetsService { - enum State { case loading case loaded(items: [Item], allLoaded: Bool) @@ -190,5 +184,4 @@ extension NftCollectionAssetsService { self.price = price } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewController.swift index a8d92a8d81..ef59e452d9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import SnapKit -import RxSwift -import RxCocoa -import ThemeKit import ComponentKit -import SectionsTableView import HUD +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class NftCollectionAssetsViewController: ThemeViewController { private let viewModel: NftCollectionAssetsViewModel @@ -25,7 +25,8 @@ class NftCollectionAssetsViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -108,27 +109,25 @@ class NftCollectionAssetsViewController: ThemeViewController { let module = NftAssetModule.viewController(providerCollectionUid: providerCollectionUid, nftUid: viewItem.nftUid) parentNavigationController?.pushViewController(module, animated: true) } - } extension NftCollectionAssetsViewController: SectionsDataSource { - private func row(leftViewItem: NftDoubleCell.ViewItem, rightViewItem: NftDoubleCell.ViewItem?, isLast: Bool) -> RowProtocol { Row( - id: "token-\(leftViewItem.nftUid.uid)-\(rightViewItem?.nftUid.uid ?? "nil")", - hash: "\(leftViewItem.hash)-\(rightViewItem?.hash ?? "nil")", - dynamicHeight: { width in - NftDoubleCell.height(containerWidth: width, isLast: isLast) - }, - bind: { [weak self] cell, _ in - cell.bind(leftViewItem: leftViewItem, rightViewItem: rightViewItem) { [weak self] viewItem in - self?.openAsset(viewItem: viewItem) - } - - if isLast { - self?.viewModel.onReachBottom() - } + id: "token-\(leftViewItem.nftUid.uid)-\(rightViewItem?.nftUid.uid ?? "nil")", + hash: "\(leftViewItem.hash)-\(rightViewItem?.hash ?? "nil")", + dynamicHeight: { width in + NftDoubleCell.height(containerWidth: width, isLast: isLast) + }, + bind: { [weak self] cell, _ in + cell.bind(leftViewItem: leftViewItem, rightViewItem: rightViewItem) { [weak self] viewItem in + self?.openAsset(viewItem: viewItem) } + + if isLast { + self?.viewModel.onReachBottom() + } + } ) } @@ -138,20 +137,20 @@ extension NftCollectionAssetsViewController: SectionsDataSource { let doubleRowCount = assetViewItems.count / 2 let hasSingleRow = assetViewItems.count % 2 == 1 - for i in 0.. RowProtocol { Row( - id: "spinner", - height: 24 + id: "spinner", + height: 24 ) } func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let viewItem = viewItem { + if let viewItem { let assetsSection = Section( - id: "main", - rows: rows(assetViewItems: viewItem.assetViewItems) + id: "main", + rows: rows(assetViewItems: viewItem.assetViewItems) ) sections.append(assetsSection) if !viewItem.allLoaded { let spinnerSection = Section( - id: "spinner", - footerState: .marginColor(height: .margin32, color: .clear), - rows: [ - spinnerRow() - ] + id: "spinner", + footerState: .marginColor(height: .margin32, color: .clear), + rows: [ + spinnerRow(), + ] ) sections.append(spinnerSection) @@ -192,5 +191,4 @@ extension NftCollectionAssetsViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewModel.swift index 5ed13d5f19..17c103fa46 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Assets/NftCollectionAssetsViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class NftCollectionAssetsViewModel { private let service: NftCollectionAssetsService @@ -25,10 +25,10 @@ class NftCollectionAssetsViewModel { viewItemRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .loaded(let items, let allLoaded): + case let .loaded(items, allLoaded): let viewItem = ViewItem( - assetViewItems: items.map { assetViewItem(item: $0) }, - allLoaded: allLoaded + assetViewItems: items.map { assetViewItem(item: $0) }, + allLoaded: allLoaded ) viewItemRelay.accept(viewItem) @@ -59,21 +59,19 @@ class NftCollectionAssetsViewModel { } return NftDoubleCell.ViewItem( - providerCollectionUid: asset.providerCollectionUid, - nftUid: asset.nftUid, - imageUrl: asset.previewImageUrl, - name: asset.displayName, - count: nil, - onSale: asset.saleInfo != nil, - coinPrice: coinPrice, - fiatPrice: fiatPrice + providerCollectionUid: asset.providerCollectionUid, + nftUid: asset.nftUid, + imageUrl: asset.previewImageUrl, + name: asset.displayName, + count: nil, + onSale: asset.saleInfo != nil, + coinPrice: coinPrice, + fiatPrice: fiatPrice ) } - } extension NftCollectionAssetsViewModel { - var viewItemDriver: Driver { viewItemRelay.asDriver() } @@ -97,14 +95,11 @@ extension NftCollectionAssetsViewModel { func onReachBottom() { service.loadMore() } - } extension NftCollectionAssetsViewModel { - struct ViewItem { let assetViewItems: [NftDoubleCell.ViewItem] let allLoaded: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionModule.swift index f9b9c075cd..9356a6f434 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionModule.swift @@ -1,9 +1,8 @@ -import UIKit import MarketKit import ThemeKit +import UIKit struct NftCollectionModule { - static func viewController(blockchainType: BlockchainType, providerCollectionUid: String) -> UIViewController? { let service = NftCollectionService() let viewModel = NftCollectionViewModel(service: service) @@ -16,17 +15,15 @@ struct NftCollectionModule { let activityController = NftActivityModule.viewController(eventListType: .collection(blockchainType: blockchainType, providerUid: providerCollectionUid)) return NftCollectionViewController( - viewModel: viewModel, - overviewController: overviewController, - assetsController: assetsController, - activityController: activityController + viewModel: viewModel, + overviewController: overviewController, + assetsController: assetsController, + activityController: activityController ) } - } extension NftCollectionModule { - enum Tab: Int, CaseIterable { case overview case assets @@ -40,5 +37,4 @@ extension NftCollectionModule { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionService.swift index 7dbeef884c..6676b62c2c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionService.swift @@ -1,14 +1,10 @@ -import RxSwift import RxRelay +import RxSwift class NftCollectionService { private let disposeBag = DisposeBag() - init() { - } - + init() {} } -extension NftCollectionService { - -} +extension NftCollectionService {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewController.swift index 7bac2b37dd..c42d863b7a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewController.swift @@ -1,11 +1,11 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import SnapKit -import RxSwift -import RxCocoa import HUD -import ComponentKit +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class NftCollectionViewController: ThemeViewController { private let viewModel: NftCollectionViewModel @@ -29,7 +29,8 @@ class NftCollectionViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -92,5 +93,4 @@ class NftCollectionViewController: ThemeViewController { case .activity: return activityController } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewModel.swift index 8bb60b4706..6a6628421e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/NftCollectionViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class NftCollectionViewModel { private let service: NftCollectionService @@ -9,9 +9,6 @@ class NftCollectionViewModel { init(service: NftCollectionService) { self.service = service } - } -extension NftCollectionViewModel { - -} +extension NftCollectionViewModel {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewModule.swift index a7b451f389..1eec20f594 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewModule.swift @@ -1,27 +1,25 @@ import MarketKit struct NftCollectionOverviewModule { - static func viewController(blockchainType: BlockchainType, providerCollectionUid: String) -> NftCollectionOverviewViewController? { guard let baseToken = try? App.shared.marketKit.token(query: TokenQuery(blockchainType: blockchainType, tokenType: .native)) else { return nil } let coinService = CoinService( - token: baseToken, - currencyManager: App.shared.currencyManager, - marketKit: App.shared.marketKit + token: baseToken, + currencyManager: App.shared.currencyManager, + marketKit: App.shared.marketKit ) let service = NftCollectionOverviewService( - blockchainType: blockchainType, - providerCollectionUid: providerCollectionUid, - nftMetadataManager: App.shared.nftMetadataManager, - marketKit: App.shared.marketKit + blockchainType: blockchainType, + providerCollectionUid: providerCollectionUid, + nftMetadataManager: App.shared.nftMetadataManager, + marketKit: App.shared.marketKit ) let viewModel = NftCollectionOverviewViewModel(service: service, coinService: coinService) return NftCollectionOverviewViewController(viewModel: viewModel, urlManager: UrlManager(inApp: true)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewService.swift index 4f470b2e4f..af89f3c2db 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewService.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class NftCollectionOverviewService { let blockchainType: BlockchainType @@ -31,20 +31,18 @@ class NftCollectionOverviewService { state = .loading nftMetadataManager.collectionMetadataSingle(blockchainType: blockchainType, providerUid: providerCollectionUid) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] collection in - let item = Item(collection: collection) - self?.state = .completed(item) - }, onError: { [weak self] error in - self?.state = .failed(error) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] collection in + let item = Item(collection: collection) + self?.state = .completed(item) + }, onError: { [weak self] error in + self?.state = .failed(error) + }) + .disposed(by: disposeBag) } - } extension NftCollectionOverviewService { - var stateObservable: Observable> { stateRelay.asObservable() } @@ -55,7 +53,8 @@ extension NftCollectionOverviewService { var providerLink: ProviderLink? { guard let title = nftMetadataManager.providerTitle(blockchainType: blockchainType), - let link = nftMetadataManager.collectionLink(blockchainType: blockchainType, providerUid: providerCollectionUid) else { + let link = nftMetadataManager.collectionLink(blockchainType: blockchainType, providerUid: providerCollectionUid) + else { return nil } @@ -65,13 +64,10 @@ extension NftCollectionOverviewService { func resync() { sync() } - } extension NftCollectionOverviewService { - struct Item { let collection: NftCollectionMetadata } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewController.swift index cb2e28ef7e..50e91547b1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewController.swift @@ -147,12 +147,12 @@ class NftCollectionOverviewViewController: ThemeViewController { extension NftCollectionOverviewViewController: SectionsDataSource { private func logoHeaderRow(viewItem: NftCollectionOverviewViewModel.ViewItem) -> RowProtocol { Row( - id: "logo-header", - height: LogoHeaderCell.height, - bind: { cell, _ in - cell.set(imageUrl: viewItem.logoImageUrl) - cell.title = viewItem.name - } + id: "logo-header", + height: LogoHeaderCell.height, + bind: { cell, _ in + cell.set(imageUrl: viewItem.logoImageUrl) + cell.title = viewItem.name + } ) } @@ -161,14 +161,14 @@ extension NftCollectionOverviewViewController: SectionsDataSource { var marketCards = [MarketCardView.ViewItem]() marketCards.append(contentsOf: - [ - statCharts.countItems, - statCharts.floorPriceItems, - statCharts.oneDayVolumeItems, - statCharts.oneDaySalesItems, - ].compactMap { - $0 - } + [ + statCharts.countItems, + statCharts.floorPriceItems, + statCharts.oneDayVolumeItems, + statCharts.oneDaySalesItems, + ].compactMap { + $0 + } ) guard !marketCards.isEmpty else { @@ -179,22 +179,22 @@ extension NftCollectionOverviewViewController: SectionsDataSource { chunks.enumerated().forEach { index, marketCards in let isLast = index == chunks.count - 1 sections.append( - Section( - id: "chart_section_\(index)", - footerState: .margin(height: isLast ? .margin24 : .margin8), - rows: [ - Row( - id: "chart_row_\(index)", - height: MarketCardView.height, - bind: { cell, _ in - cell.clear() - marketCards.forEach { - cell.append(viewItem: $0) - } - } - ), - ] - ) + Section( + id: "chart_section_\(index)", + footerState: .margin(height: isLast ? .margin24 : .margin8), + rows: [ + Row( + id: "chart_row_\(index)", + height: MarketCardView.height, + bind: { cell, _ in + cell.clear() + marketCards.forEach { + cell.append(viewItem: $0) + } + } + ), + ] + ) ) } @@ -204,7 +204,7 @@ extension NftCollectionOverviewViewController: SectionsDataSource { private func royaltySection(viewItem: NftCollectionOverviewViewModel.ViewItem) -> SectionProtocol? { let rowTexts = [ viewItem.royalty.map { ("nft_collection.overview.royalty".localized, $0) }, - viewItem.inceptionDate.map { ("nft_collection.overview.inception_date".localized, $0) } + viewItem.inceptionDate.map { ("nft_collection.overview.inception_date".localized, $0) }, ].compactMap { $0 } guard rowTexts.count > 0 else { @@ -212,17 +212,17 @@ extension NftCollectionOverviewViewController: SectionsDataSource { } return Section( - id: "royalty", - footerState: .margin(height: .margin24), - rows: rowTexts.enumerated().map { index, tuple in - tableView.universalRow48( - id: "text_\(index)", - title: .subhead2(tuple.0), - value: .subhead1(tuple.1), - isFirst: index == 0, - isLast: index == rowTexts.count - 1 - ) - } + id: "royalty", + footerState: .margin(height: .margin24), + rows: rowTexts.enumerated().map { index, tuple in + tableView.universalRow48( + id: "text_\(index)", + title: .subhead2(tuple.0), + value: .subhead1(tuple.1), + isFirst: index == 0, + isLast: index == rowTexts.count - 1 + ) + } ) } @@ -230,155 +230,156 @@ extension NftCollectionOverviewViewController: SectionsDataSource { descriptionTextCell.contentText = NSAttributedString(string: description, attributes: [.font: UIFont.subhead2, .foregroundColor: UIColor.themeGray]) let descriptionRow = StaticRow( - cell: descriptionTextCell, - id: "description", - dynamicHeight: { [weak self] containerWidth in - self?.descriptionTextCell.cellHeight(containerWidth: containerWidth) ?? 0 - } + cell: descriptionTextCell, + id: "description", + dynamicHeight: { [weak self] containerWidth in + self?.descriptionTextCell.cellHeight(containerWidth: containerWidth) ?? 0 + } ) return Section( - id: "description", - footerState: .margin(height: .margin24), - rows: [ - tableView.headerInfoRow(id: "header_nft_collection.overview.description", title: "nft_collection.overview.description".localized), - descriptionRow, - ] + id: "description", + footerState: .margin(height: .margin24), + rows: [ + tableView.headerInfoRow(id: "header_nft_collection.overview.description", title: "nft_collection.overview.description".localized), + descriptionRow, + ] ) } private func contractsSection(viewItems: [NftCollectionOverviewViewModel.ContractViewItem]) -> SectionProtocol { Section( - id: "contracts", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin24), - rows: [ - tableView.headerInfoRow(id: "header.nft_collection.overview.contracts", title: "nft_collection.overview.contracts".localized), - ] + viewItems.enumerated().map { index, viewItem in - CellBuilderNew.row( - rootElement: .hStack([ - .image32 { (component: ImageComponent) in - component.setImage(urlString: viewItem.iconUrl, placeholder: UIImage(named: "placeholder_rectangle_32")) + id: "contracts", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin24), + rows: [ + tableView.headerInfoRow(id: "header.nft_collection.overview.contracts", title: "nft_collection.overview.contracts".localized), + ] + viewItems.enumerated().map { index, viewItem in + CellBuilderNew.row( + rootElement: .hStack([ + .image32 { (component: ImageComponent) in + component.setImage(urlString: viewItem.iconUrl, placeholder: UIImage(named: "placeholder_rectangle_32")) + }, + .vStackCentered([ + .hStack([ + .text { component in + component.font = .body + component.textColor = .themeLeah + component.text = viewItem.name + component.setContentHuggingPriority(.required, for: .horizontal) }, - .vStackCentered([ - .hStack([ - .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = viewItem.name - component.setContentHuggingPriority(.required, for: .horizontal) - }, - .margin8, - .badge { component in - component.isHidden = viewItem.schema == nil - component.badgeView.set(style: .small) - component.badgeView.text = viewItem.schema - }, - .margin0, - .text { _ in } - ]), - .margin(1), - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = viewItem.reference.shortened - } - ]), - .secondaryCircleButton { (component: SecondaryCircleButtonComponent) in - component.button.set(image: UIImage(named: "copy_20")) - component.onTap = { - CopyHelper.copyAndNotify(value: viewItem.reference) - } + .margin8, + .badge { component in + component.isHidden = viewItem.schema == nil + component.badgeView.set(style: .small) + component.badgeView.text = viewItem.schema }, - .secondaryCircleButton { (component: SecondaryCircleButtonComponent) in - if let explorerUrl = viewItem.explorerUrl { - component.isHidden = false - component.button.set(image: UIImage(named: "globe_20")) - component.onTap = { [weak self] in - self?.urlManager.open(url: explorerUrl, from: self?.parentNavigationController) - } - } else { - component.isHidden = true - } - } + .margin0, + .text { _ in }, ]), - tableView: tableView, - id: "contract-\(index)", - height: .heightCell56, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: index == 0, isLast: index == viewItems.count - 1) + .margin(1), + .text { component in + component.font = .subhead2 + component.textColor = .themeGray + component.text = viewItem.reference.shortened + }, + ]), + .secondaryCircleButton { (component: SecondaryCircleButtonComponent) in + component.button.set(image: UIImage(named: "copy_20")) + component.onTap = { + CopyHelper.copyAndNotify(value: viewItem.reference) } - ) - } + }, + .secondaryCircleButton { (component: SecondaryCircleButtonComponent) in + if let explorerUrl = viewItem.explorerUrl { + component.isHidden = false + component.button.set(image: UIImage(named: "globe_20")) + component.onTap = { [weak self] in + self?.urlManager.open(url: explorerUrl, from: self?.parentNavigationController) + } + } else { + component.isHidden = true + } + }, + ]), + tableView: tableView, + id: "contract-\(index)", + height: .heightCell56, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: index == 0, isLast: index == viewItems.count - 1) + } + ) + } ) } private func linksSections(viewItems: [NftCollectionOverviewViewModel.LinkViewItem]) -> [SectionProtocol] { [ Section( - id: "links-header", - rows: [ - tableView.headerInfoRow(id: "header.nft_collection.overview.links", title: "nft_collection.overview.links".localized), - ] + id: "links-header", + rows: [ + tableView.headerInfoRow(id: "header.nft_collection.overview.links", title: "nft_collection.overview.links".localized), + ] ), Section( - id: "links", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin24), - rows: viewItems.enumerated().map { index, link in - linkRow( - iconImage: linkIcon(type: link.type), - title: linkTitle(type: link.type), - url: link.url, - isFirst: index == 0, - isLast: index == viewItems.count - 1 - ) - } + id: "links", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin24), + rows: viewItems.enumerated().map { index, link in + linkRow( + iconImage: linkIcon(type: link.type), + title: linkTitle(type: link.type), + url: link.url, + isFirst: index == 0, + isLast: index == viewItems.count - 1 + ) + } ), ] } private func linkRow(iconImage: UIImage?, title: String, url: String, isFirst: Bool, isLast: Bool) -> RowProtocol { tableView.universalRow48( - id: "link-\(title)", - image: .local(iconImage?.withTintColor(.themeGray)), - title: .body(title), - accessoryType: .disclosure, - autoDeselect: true, - isFirst: isFirst, - isLast: isLast, - action: { [weak self] in - self?.openLink(url: url) - }) + id: "link-\(title)", + image: .local(iconImage?.withTintColor(.themeGray)), + title: .body(title), + accessoryType: .disclosure, + autoDeselect: true, + isFirst: isFirst, + isLast: isLast, + action: { [weak self] in + self?.openLink(url: url) + } + ) } private func poweredBySection(text: String) -> SectionProtocol { Section( - id: "powered-by", - headerState: .margin(height: .margin8), - rows: [ - Row( - id: "powered-by", - dynamicHeight: { containerWidth in - BrandFooterCell.height(containerWidth: containerWidth, title: text) - }, - bind: { cell, _ in - cell.title = text - } - ), - ] + id: "powered-by", + headerState: .margin(height: .margin8), + rows: [ + Row( + id: "powered-by", + dynamicHeight: { containerWidth in + BrandFooterCell.height(containerWidth: containerWidth, title: text) + }, + bind: { cell, _ in + cell.title = text + } + ), + ] ) } public func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let viewItem = viewItem { + if let viewItem { let logoHeaderSection = Section( - id: "logo-header", - rows: [ - logoHeaderRow(viewItem: viewItem), - ] + id: "logo-header", + rows: [ + logoHeaderRow(viewItem: viewItem), + ] ) sections.append(logoHeaderSection) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewModel.swift index c28544ba7b..0c7540b413 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/NftCollection/Overview/NftCollectionOverviewViewModel.swift @@ -29,7 +29,7 @@ class NftCollectionOverviewViewModel { viewItemRelay.accept(nil) loadingRelay.accept(true) syncErrorRelay.accept(false) - case .completed(let item): + case let .completed(item): viewItemRelay.accept(viewItem(item: item)) loadingRelay.accept(false) syncErrorRelay.accept(false) @@ -44,24 +44,24 @@ class NftCollectionOverviewViewModel { let collection = item.collection return ViewItem( - logoImageUrl: collection.imageUrl ?? collection.thumbnailImageUrl, - name: collection.name, - description: collection.description, - contracts: collection.contracts.map { contractViewItem(contract: $0) }, - links: linkViewItems(collection: collection), - statsViewItems: statViewItem(collection: collection), - royalty: collection.royalty.flatMap { ValueFormatter.instance.format(percentValue: $0, showSign: false) }, - inceptionDate: collection.inceptionDate.map {DateFormatter.cachedFormatter(format: "MMMM d, yyyy").string(from: $0) } + logoImageUrl: collection.imageUrl ?? collection.thumbnailImageUrl, + name: collection.name, + description: collection.description, + contracts: collection.contracts.map { contractViewItem(contract: $0) }, + links: linkViewItems(collection: collection), + statsViewItems: statViewItem(collection: collection), + royalty: collection.royalty.flatMap { ValueFormatter.instance.format(percentValue: $0, showSign: false) }, + inceptionDate: collection.inceptionDate.map { DateFormatter.cachedFormatter(format: "MMMM d, yyyy").string(from: $0) } ) } private func contractViewItem(contract: NftContractMetadata) -> ContractViewItem { ContractViewItem( - iconUrl: service.blockchainType.imageUrl, - name: contract.name, - schema: contract.schema, - reference: contract.address, - explorerUrl: service.blockchain?.explorerUrl(reference: contract.address) + iconUrl: service.blockchainType.imageUrl, + name: contract.name, + schema: contract.schema, + reference: contract.address, + explorerUrl: service.blockchain?.explorerUrl(reference: contract.address) ) } @@ -101,33 +101,33 @@ class NftCollectionOverviewViewModel { let floorPriceViewItem = collection.floorPrice.map { floorPrice -> MarketCardView.ViewItem in let floorPriceInCurrency = coinService.rate - .map { - ValueFormatter.instance - .formatShort(currency: $0.currency, value: $0.value * floorPrice.value) - } ?? "n/a".localized + .map { + ValueFormatter.instance + .formatShort(currency: $0.currency, value: $0.value * floorPrice.value) + } ?? "n/a".localized return MarketCardView.ViewItem( title: "nft_collection.overview.floor_price".localized, value: string(nftPrice: floorPrice), - description:floorPriceInCurrency + description: floorPriceInCurrency ) - } ?? MarketCardView.ViewItem( - title: "nft_collection.overview.floor_price".localized, - value: "---", - description:"n/a".localized + } ?? MarketCardView.ViewItem( + title: "nft_collection.overview.floor_price".localized, + value: "---", + description: "n/a".localized ) let volumeDiff = collection.change1d - .flatMap { DiffLabel.formatted(value: $0) } + .flatMap { DiffLabel.formatted(value: $0) } let volumeColor = collection.change1d - .map { DiffLabel.color(value: $0) } + .map { DiffLabel.color(value: $0) } let volume24ViewItem = collection.volume1d.map { volume1d in MarketCardView.ViewItem( - title: "nft_collection.overview.24h_volume".localized, - value: string(nftPrice: volume1d), - description: volumeDiff, - descriptionColor: volumeColor + title: "nft_collection.overview.24h_volume".localized, + value: string(nftPrice: volume1d), + description: volumeDiff, + descriptionColor: volumeColor ) } @@ -139,17 +139,17 @@ class NftCollectionOverviewViewModel { let todaySellersViewItem = collection.sales1d.map { sales1d in MarketCardView.ViewItem( - title: "nft_collection.overview.today_sellers".localized, - value: "\(sales1d) NFT", - description: additional + title: "nft_collection.overview.today_sellers".localized, + value: "\(sales1d) NFT", + description: additional ) } return StatsViewItem( - countItems: ownerViewItem, - oneDayVolumeItems: volume24ViewItem, - floorPriceItems: floorPriceViewItem, - oneDaySalesItems: todaySellersViewItem + countItems: ownerViewItem, + oneDayVolumeItems: volume24ViewItem, + floorPriceItems: floorPriceViewItem, + oneDaySalesItems: todaySellersViewItem ) } @@ -161,7 +161,6 @@ class NftCollectionOverviewViewModel { let coinValue = CoinValue(kind: .token(token: price.token), value: price.value) return ValueFormatter.instance.formatShort(coinValue: coinValue) } - } extension NftCollectionOverviewViewModel { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/DuressMode/DuressModeViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/DuressMode/DuressModeViewModel.swift index 026e29ca52..037d12766d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/DuressMode/DuressModeViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/DuressMode/DuressModeViewModel.swift @@ -13,7 +13,7 @@ class DuressModeViewModel: ObservableObject { let sortedAccounts = accountManager.accounts.sorted { $0.name.lowercased() < $1.name.lowercased() } regularAccounts = sortedAccounts.filter { !$0.watchAccount } - watchAccounts = sortedAccounts.filter { $0.watchAccount } + watchAccounts = sortedAccounts.filter(\.watchAccount) } var biometryType: BiometryType? { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Manage/SetPasscodeViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Manage/SetPasscodeViewModel.swift index b6ae7e24ca..2e4dcf0353 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Manage/SetPasscodeViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Manage/SetPasscodeViewModel.swift @@ -35,7 +35,7 @@ class SetPasscodeViewModel: ObservableObject { var title: String { "" } var passcodeDescription: String { "" } var confirmDescription: String { "" } - func isCurrent(passcode: String) -> Bool { false } + func isCurrent(passcode _: String) -> Bool { false } func onEnter(passcode _: String) {} func onCancel() {} @@ -49,7 +49,7 @@ class SetPasscodeViewModel: ObservableObject { syncDescription() errorText = "set_passcode.invalid_confirmation".localized } - } else if passcodeManager.has(passcode: passcode) && !isCurrent(passcode: passcode) { + } else if passcodeManager.has(passcode: passcode), !isCurrent(passcode: passcode) { self.passcode = "" errorText = "set_passcode.already_used".localized diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/BaseUnlockViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/BaseUnlockViewModel.swift index 12137ca989..93a47e1173 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/BaseUnlockViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/BaseUnlockViewModel.swift @@ -27,6 +27,7 @@ class BaseUnlockViewModel: ObservableObject { syncErrorText() } } + @Published var shakeTrigger: Int = 0 let finishSubject = PassthroughSubject() diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/ModuleUnlockViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/ModuleUnlockViewModel.swift index 76af1a33dd..9b5befbda3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/ModuleUnlockViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Passcode/Unlock/ModuleUnlockViewModel.swift @@ -14,7 +14,7 @@ class ModuleUnlockViewModel: BaseUnlockViewModel { passcodeManager.isValid(passcode: passcode) } - override func onEnterValid(passcode: String) { + override func onEnterValid(passcode _: String) { onUnlock() finishSubject.send(false) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderView.swift index dceb9f3652..b10111b1b6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderView.swift @@ -1,14 +1,14 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit import RxSwift +import SnapKit +import ThemeKit +import UIKit class PlaceholderView: UIView { private let disposeBag = DisposeBag() private let reachabilityViewModel: ReachabilityViewModel? - private var retryAction: (() -> ())? + private var retryAction: (() -> Void)? private let stackView = UIStackView() private let topSpacer = UIView() @@ -70,7 +70,8 @@ class PlaceholderView: UIView { label.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -100,7 +101,7 @@ class PlaceholderView: UIView { return button } - func configureSyncError(title: String = "sync_error".localized, action: (() -> ())? = nil) { + func configureSyncError(title: String = "sync_error".localized, action: (() -> Void)? = nil) { retryAction = action if let driver = reachabilityViewModel?.retryDriver { @@ -113,10 +114,10 @@ class PlaceholderView: UIView { text = title addPrimaryButton( - style: .yellow, - title: "button.retry".localized, - target: self, - action: #selector(retry) + style: .yellow, + title: "button.retry".localized, + target: self, + action: #selector(retry) ) } @@ -135,13 +136,10 @@ class PlaceholderView: UIView { } else { HudHelper.instance.show(banner: .noInternet) } - } - } extension PlaceholderView { - enum LayoutType { case upperMiddle case keyboard @@ -161,5 +159,4 @@ extension PlaceholderView { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderViewModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderViewModule.swift index 513003a9d2..569fa9ae68 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderViewModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/PlaceholderViewModule.swift @@ -1,9 +1,7 @@ -class PlaceholderViewModule { - +enum PlaceholderViewModule { static func reachabilityView(layoutType: PlaceholderView.LayoutType = .upperMiddle) -> PlaceholderView { let service = ReachabilityService(reachabilityManager: App.shared.reachabilityManager) let viewModel = ReachabilityViewModel(service: service) return PlaceholderView(layoutType: layoutType, reachabilityViewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityService.swift index 991eb900a0..68d417775e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityService.swift @@ -15,5 +15,4 @@ class ReachabilityService { var reachabilityObservable: Observable { reachabilityManager.reachabilityObservable } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityViewModel.swift index 1b1dca1601..18d34fa822 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Placeholder/ReachabilityViewModel.swift @@ -1,34 +1,33 @@ import HsToolKit -import RxSwift import RxCocoa import RxRelay +import RxSwift class ReachabilityViewModel { private let disposeBag = DisposeBag() private let service: ReachabilityService - private let retryRelay = PublishRelay<()>() + private let retryRelay = PublishRelay() init(service: ReachabilityService) { self.service = service service.reachabilityObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] reachable in - if reachable { - self?.retryRelay.accept(()) - } - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] reachable in + if reachable { + self?.retryRelay.accept(()) + } + }) + .disposed(by: disposeBag) } var isReachable: Bool { service.isReachable } - var retryDriver: Driver<()> { + var retryDriver: Driver { retryRelay.asDriver(onErrorJustReturn: ()) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/CoinProChartModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/CoinProChartModule.swift index d64cfd3d82..39ddbf3e59 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/CoinProChartModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/CoinProChartModule.swift @@ -1,32 +1,29 @@ -import UIKit -import RxSwift import Chart import MarketKit +import RxSwift +import UIKit class CoinProChartModule { - static func viewController(coin: Coin, type: ProChartType) -> UIViewController { let chartFetcher = ProChartFetcher(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, coin: coin, type: type) let chartService = MetricChartService( - chartFetcher: chartFetcher, - interval: .month1 + chartFetcher: chartFetcher, + interval: .month1 ) let factory = MetricChartFactory(currentLocale: LanguageManager.shared.currentLocale) let chartViewModel = MetricChartViewModel(service: chartService, factory: factory) return MetricChartViewController( - title: type.title, - viewModel: chartViewModel, - configuration: type.chartConfiguration + title: type.title, + viewModel: chartViewModel, + configuration: type.chartConfiguration ).toBottomSheet } - } extension CoinProChartModule { - enum ProChartType { case cexVolume case dexVolume @@ -54,5 +51,4 @@ extension CoinProChartModule { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/ProChartFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/ProChartFetcher.swift index dba01e3934..752e9f738c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/ProChartFetcher.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProCharts/ProChartFetcher.swift @@ -1,6 +1,6 @@ +import Chart import Foundation import MarketKit -import Chart class ProChartFetcher { private let marketKit: MarketKit.Kit @@ -14,11 +14,9 @@ class ProChartFetcher { self.coin = coin self.type = type } - } extension ProChartFetcher: IMetricChartFetcher { - var intervals: [HsTimePeriod] { switch type { case .cexVolume, .dexVolume, .dexLiquidity, .activeAddresses, .txCount: @@ -40,44 +38,43 @@ extension ProChartFetcher: IMetricChartFetcher { case .cexVolume: let data = try await marketKit.cexVolumes(coinUid: coin.uid, currencyCode: currencyManager.baseCurrency.code, timePeriod: interval) return MetricChartModule.ItemData( - items: data.points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, - type: .aggregated(value: data.aggregatedValue) + items: data.points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, + type: .aggregated(value: data.aggregatedValue) ) case .dexVolume: let data = try await marketKit.dexVolumes(coinUid: coin.uid, currencyCode: currencyManager.baseCurrency.code, timePeriod: interval) return MetricChartModule.ItemData( - items: data.points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, - type: .aggregated(value: data.aggregatedValue) + items: data.points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, + type: .aggregated(value: data.aggregatedValue) ) case .dexLiquidity: let points = try await marketKit.dexLiquidity(coinUid: coin.uid, currencyCode: currencyManager.baseCurrency.code, timePeriod: interval) return MetricChartModule.ItemData( - items: points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, - type: .regular + items: points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, + type: .regular ) case .activeAddresses: let points = try await marketKit.activeAddresses(coinUid: coin.uid, timePeriod: interval) return MetricChartModule.ItemData( - items: points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, - type: .regular + items: points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, + type: .regular ) case .txCount: let data = try await marketKit.transactions(coinUid: coin.uid, timePeriod: interval) let volumes = data.points.map { $0.volume ?? 0 } return MetricChartModule.ItemData( - items: data.points.map { - MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) - }, - indicators: [ChartData.volume: volumes], - type: .aggregated(value: data.aggregatedValue) + items: data.points.map { + MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) + }, + indicators: [ChartData.volume: volumes], + type: .aggregated(value: data.aggregatedValue) ) case .tvl: let points = try await marketKit.marketInfoTvl(coinUid: coin.uid, currencyCode: currencyManager.baseCurrency.code, timePeriod: interval) return MetricChartModule.ItemData( - items: points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, - type: .regular + items: points.map { MetricChartModule.Item(value: $0.value, timestamp: $0.timestamp) }, + type: .regular ) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationAdapter.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationAdapter.swift index 17ec223520..f9efca9a6b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationAdapter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationAdapter.swift @@ -1,8 +1,8 @@ +import Alamofire import Foundation import HsToolKit -import RxSwift -import Alamofire import ObjectMapper +import RxSwift class ProFeaturesAuthorizationAdapter { private let apiUrl = AppConfig.marketApiUrl @@ -13,16 +13,14 @@ class ProFeaturesAuthorizationAdapter { self.networkManager = networkManager headers = AppConfig.hsProviderApiKey.flatMap { HTTPHeaders([HTTPHeader(name: "apikey", value: $0)]) } } - } extension ProFeaturesAuthorizationAdapter { - // Get AuthKey func message(address: String) -> Single { let parameters: Parameters = [ - "address": address + "address": address, ] return networkManager.single(url: "\(apiUrl)/v1/auth/get-key", method: .get, parameters: parameters, headers: headers).map { (response: AuthorizeResponse) in response.key @@ -34,34 +32,29 @@ extension ProFeaturesAuthorizationAdapter { func authenticate(address: String, signature: String) -> Single { let parameters: Parameters = [ "address": address, - "signature": signature + "signature": signature, ] return networkManager.single(url: "\(apiUrl)/v1/auth/authenticate", method: .post, parameters: parameters, headers: headers).map { (response: AuthenticateResponse) in response.key } } - } extension ProFeaturesAuthorizationAdapter { - private class AuthorizeResponse: ImmutableMappable { public let key: String - required public init(map: Map) throws { + public required init(map: Map) throws { key = try map.value("key") } - } private class AuthenticateResponse: ImmutableMappable { public let key: String - required public init(map: Map) throws { + public required init(map: Map) throws { key = try map.value("token") } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationManager.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationManager.swift index 253505a104..5c72b4ce2e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesAuthorizationManager.swift @@ -1,10 +1,10 @@ -import UIKit +import BigInt +import EvmKit +import HsExtensions import RxCocoa import RxRelay import RxSwift -import EvmKit -import BigInt -import HsExtensions +import UIKit class ProFeaturesAuthorizationManager { static let contractAddress = try! EvmKit.Address(hex: "0x495f947276749ce646f68ac8c248420045cb7b5e") @@ -32,29 +32,29 @@ class ProFeaturesAuthorizationManager { private func sortedAccountData() -> [AccountData] { let accounts = accountManager - .accounts - .filter { account in - account.type.mnemonicSeed != nil - } + .accounts + .filter { account in + account.type.mnemonicSeed != nil + } guard !accounts.isEmpty, let active = accountManager.activeAccount else { - return [] } return accounts - .sorted { account, account2 in - account.id == active.id - } - .compactMap { account in - if let seed = account.type.mnemonicSeed, - let address = try? Signer.address(seed: seed, chain: .ethereum) { - return AccountData(accountId: account.id, address: address) - } - return nil + .sorted { account, _ in + account.id == active.id + } + .compactMap { account in + if let seed = account.type.mnemonicSeed, + let address = try? Signer.address(seed: seed, chain: .ethereum) + { + return AccountData(accountId: account.id, address: address) } + return nil + } } private func tokenHolder(provider: Eip1155Provider, contractAddress: EvmKit.Address, tokenId: BigUInt, accountData: [AccountData], index: Int = 0) -> Single { @@ -63,19 +63,17 @@ class ProFeaturesAuthorizationManager { } return provider.getBalanceOf(contractAddress: contractAddress, tokenId: tokenId, address: accountData[index].address) - .flatMap { [weak self] balance in - if balance != 0 { - return Single.just(accountData[index]) - } else { - return self?.tokenHolder(provider: provider, contractAddress: contractAddress, tokenId: tokenId, accountData: accountData, index: index + 1) ?? Single.just(nil) - } + .flatMap { [weak self] balance in + if balance != 0 { + return Single.just(accountData[index]) + } else { + return self?.tokenHolder(provider: provider, contractAddress: contractAddress, tokenId: tokenId, accountData: accountData, index: index + 1) ?? Single.just(nil) } + } } - } extension ProFeaturesAuthorizationManager { - var sessionKeyObservable: Observable { sessionKeyRelay.asObservable() } @@ -89,13 +87,13 @@ extension ProFeaturesAuthorizationManager { sessionKeyRelay.accept(SessionKey(type: type, key: sessionKey)) } - func nftHolder(type: NftType) -> Single { + func nftHolder(type _: NftType) -> Single { let accountData = sortedAccountData() guard !accountData.isEmpty, let httpSyncSource = evmSyncSourceManager.httpSyncSource(blockchainType: .ethereum), - let provider = try? Eip1155Provider.instance(rpcSource: httpSyncSource.rpcSource) else { - + let provider = try? Eip1155Provider.instance(rpcSource: httpSyncSource.rpcSource) + else { return Single.just(nil) } @@ -104,7 +102,8 @@ extension ProFeaturesAuthorizationManager { func sign(accountData: AccountData, data: Data) -> String? { guard let account = accountManager.account(id: accountData.accountId), - let seed = account.type.mnemonicSeed else { + let seed = account.type.mnemonicSeed + else { return nil } @@ -115,11 +114,9 @@ extension ProFeaturesAuthorizationManager { func clearSessionKey(type: NftType?) { storage.clear(type: type) } - } extension ProFeaturesAuthorizationManager { - enum NftType: String, CaseIterable { case mountainYak } @@ -133,5 +130,4 @@ extension ProFeaturesAuthorizationManager { let type: NftType let key: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesStorage.swift b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesStorage.swift index 06e68cd61e..89475e1ce9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/ProFeatures/ProFeaturesStorage.swift @@ -6,16 +6,15 @@ class ProFeaturesStorage { init(keychainStorage: KeychainStorage) { self.keychainStorage = keychainStorage } - } extension ProFeaturesStorage { - func getAll() -> [ProFeaturesAuthorizationManager.NftType: SessionKey] { var keys = [ProFeaturesAuthorizationManager.NftType: SessionKey]() for type in ProFeaturesAuthorizationManager.NftType.allCases { if let raw: String = keychainStorage.value(for: type.rawValue), - let sessionKey = SessionKey(raw: raw) { + let sessionKey = SessionKey(raw: raw) + { keys[type] = sessionKey } } @@ -42,7 +41,7 @@ extension ProFeaturesStorage { } func clear(type: ProFeaturesAuthorizationManager.NftType?) { - if let type = type { + if let type { try? keychainStorage.removeValue(for: type.rawValue) return } @@ -51,11 +50,9 @@ extension ProFeaturesStorage { try? keychainStorage.removeValue(for: type.rawValue) } } - } extension ProFeaturesStorage { - struct SessionKey: CustomStringConvertible { private static let separator: Character = "_" @@ -83,8 +80,5 @@ extension ProFeaturesStorage { var rawValue: String { [accountId, address, sessionKey].joined(separator: String(SessionKey.separator)) } - } - } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseModule.swift index 85672e8ad0..ec6615f5ba 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseModule.swift @@ -1,8 +1,7 @@ -import UIKit import ThemeKit +import UIKit struct RecoveryPhraseModule { - static func viewController(account: Account) -> UIViewController? { guard let service = RecoveryPhraseService(account: account) else { return nil @@ -11,5 +10,4 @@ struct RecoveryPhraseModule { let viewModel = RecoveryPhraseViewModel(service: service) return RecoveryPhraseViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseService.swift index c244ee8787..7da07f97c7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseService.swift @@ -10,5 +10,4 @@ class RecoveryPhraseService { self.words = words self.salt = salt } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewController.swift index 5567ace27e..3ee46e9c47 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView import ComponentKit +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class RecoveryPhraseViewController: ThemeViewController { private let viewModel: RecoveryPhraseViewModel @@ -17,7 +17,8 @@ class RecoveryPhraseViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -74,11 +75,9 @@ class RecoveryPhraseViewController: ThemeViewController { visible = !visible tableView.reload() } - } extension RecoveryPhraseViewController: SectionsDataSource { - private func marginRow(id: String, height: CGFloat) -> RowProtocol { Row(id: id, height: height) } @@ -89,51 +88,51 @@ extension RecoveryPhraseViewController: SectionsDataSource { var rows: [RowProtocol] = [ tableView.highlightedDescriptionRow( - id: "warning", - text: "recovery_phrase.warning".localized(AppConfig.appName) + id: "warning", + text: "recovery_phrase.warning".localized(AppConfig.appName) ), marginRow(id: "warning-bottom-margin", height: .margin12), Row( - id: "mnemonic", - dynamicHeight: { width in - MnemonicPhraseCell.height(containerWidth: width, words: words) - }, - bind: { cell, _ in - cell.set(state: state) - }, - action: { [weak self] _ in - self?.toggle() - } - ) + id: "mnemonic", + dynamicHeight: { width in + MnemonicPhraseCell.height(containerWidth: width, words: words) + }, + bind: { cell, _ in + cell.set(state: state) + }, + action: { [weak self] _ in + self?.toggle() + } + ), ] let visible = visible if let passphrase = viewModel.passphrase { let passphraseRow = CellBuilderNew.row( - rootElement: .hStack([ - .image24 { component in - component.imageView.image = UIImage(named: "key_phrase_24")?.withTintColor(.themeGray) - }, - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = "recovery_phrase.passphrase".localized - }, - .secondaryButton { component in - component.button.set(style: .default) - component.button.setTitle(visible ? passphrase : BalanceHiddenManager.placeholder, for: .normal) - component.onTap = { - CopyHelper.copyAndNotify(value: passphrase) - } + rootElement: .hStack([ + .image24 { component in + component.imageView.image = UIImage(named: "key_phrase_24")?.withTintColor(.themeGray) + }, + .text { component in + component.font = .subhead2 + component.textColor = .themeGray + component.text = "recovery_phrase.passphrase".localized + }, + .secondaryButton { component in + component.button.set(style: .default) + component.button.setTitle(visible ? passphrase : BalanceHiddenManager.placeholder, for: .normal) + component.onTap = { + CopyHelper.copyAndNotify(value: passphrase) } - ]), - tableView: tableView, - id: "passphrase", - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - } + }, + ]), + tableView: tableView, + id: "passphrase", + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + } ) rows.append(marginRow(id: "passphrase-margin", height: .margin24)) @@ -142,11 +141,10 @@ extension RecoveryPhraseViewController: SectionsDataSource { return [ Section( - id: "main", - footerState: .margin(height: .margin32), - rows: rows - ) + id: "main", + footerState: .margin(height: .margin32), + rows: rows + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewModel.swift index 619767c102..d4139277b4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RecoveryPhrase/RecoveryPhraseViewModel.swift @@ -4,11 +4,9 @@ class RecoveryPhraseViewModel { init(service: RecoveryPhraseService) { self.service = service } - } extension RecoveryPhraseViewModel { - var words: [String] { service.words } @@ -16,5 +14,4 @@ extension RecoveryPhraseViewModel { var passphrase: String? { service.salt.isEmpty ? nil : service.salt } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreModule.swift index 8d006b26ff..048d267f08 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreModule.swift @@ -1,9 +1,8 @@ -import UIKit import ThemeKit +import UIKit struct RestoreModule { - - static func viewController(advanced: Bool = false, sourceViewController: UIViewController? = nil, returnViewController: UIViewController? = nil) -> UIViewController { + static func viewController(advanced: Bool = false, sourceViewController _: UIViewController? = nil, returnViewController: UIViewController? = nil) -> UIViewController { let mnemonicService = RestoreMnemonicService(languageManager: LanguageManager.shared) let mnemonicViewModel = RestoreMnemonicViewModel(service: mnemonicService) @@ -14,14 +13,13 @@ struct RestoreModule { let viewModel = RestoreViewModel(service: service, mnemonicViewModel: mnemonicViewModel, privateKeyViewModel: privateKeyViewModel) let viewController = RestoreViewController( - advanced: advanced, - viewModel: viewModel, - mnemonicViewModel: mnemonicViewModel, - privateKeyViewModel: privateKeyViewModel, - returnViewController: returnViewController + advanced: advanced, + viewModel: viewModel, + mnemonicViewModel: mnemonicViewModel, + privateKeyViewModel: privateKeyViewModel, + returnViewController: returnViewController ) return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreService.swift index 84c380a7c3..ac1686cab5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreService.swift @@ -8,11 +8,9 @@ class RestoreService { init(accountFactory: AccountFactory) { self.accountFactory = accountFactory } - } extension RestoreService { - var defaultAccountName: String { accountFactory.nextAccountName } @@ -21,5 +19,4 @@ extension RestoreService { let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) return trimmedName.isEmpty ? defaultAccountName : trimmedName } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewController.swift index cae47bc6e5..c24f934228 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewController.swift @@ -1,12 +1,12 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import RxSwift import RxCocoa +import RxSwift import SectionsTableView import SnapKit -import ComponentKit +import ThemeKit import UIExtensions +import UIKit class RestoreViewController: KeyboardAwareViewController { private let advanced: Bool @@ -49,7 +49,8 @@ class RestoreViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: hintView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -109,16 +110,16 @@ class RestoreViewController: KeyboardAwareViewController { wordListCell.set(backgroundStyle: .lawrence, isFirst: true, isLast: false) passphraseToggleCell.set(backgroundStyle: .lawrence, isFirst: false, isLast: true) CellBuilderNew.buildStatic( - cell: passphraseToggleCell, - rootElement: .hStack( - tableView.universalImage24Elements( - image: .local(UIImage(named: "key_phrase_24")?.withTintColor(.themeGray)), - title: .body("restore.passphrase".localized), - accessoryType: .switch { [weak self] in - self?.mnemonicViewModel.onTogglePassphrase(isOn: $0) - } - ) + cell: passphraseToggleCell, + rootElement: .hStack( + tableView.universalImage24Elements( + image: .local(UIImage(named: "key_phrase_24")?.withTintColor(.themeGray)), + title: .body("restore.passphrase".localized), + accessoryType: .switch { [weak self] in + self?.mnemonicViewModel.onTogglePassphrase(isOn: $0) + } ) + ) ) passphraseCell.set(textSecure: true) @@ -211,15 +212,15 @@ class RestoreViewController: KeyboardAwareViewController { private func syncWordListLanguageCell(wordListLanguage: String) { CellBuilderNew.buildStatic( - cell: wordListCell, - rootElement: .hStack( - tableView.universalImage24Elements( - image: .local(UIImage(named: "globe_24")?.withTintColor(.themeGray)), - title: .body("create_wallet.word_list".localized), - value: .subhead1(wordListLanguage), - accessoryType: .dropdown - ) + cell: wordListCell, + rootElement: .hStack( + tableView.universalImage24Elements( + image: .local(UIImage(named: "globe_24")?.withTintColor(.themeGray)), + title: .body("create_wallet.word_list".localized), + value: .subhead1(wordListLanguage), + accessoryType: .dropdown ) + ) ) mnemonicInputCell.set(text: mnemonicInputCell.textView.text) @@ -255,13 +256,13 @@ class RestoreViewController: KeyboardAwareViewController { private func onTapRestoreType() { let alertController = AlertRouter.module( - title: "restore.import_by".localized, - viewItems: RestoreViewModel.RestoreType.allCases.enumerated().map { index, restoreType in - AlertViewItem( - text: restoreType.title, - selected: self.restoreType == restoreType - ) - } + title: "restore.import_by".localized, + viewItems: RestoreViewModel.RestoreType.allCases.enumerated().map { _, restoreType in + AlertViewItem( + text: restoreType.title, + selected: self.restoreType == restoreType + ) + } ) { [weak self] index in self?.viewModel.onSelect(restoreType: RestoreViewModel.RestoreType.allCases[index]) } @@ -273,172 +274,169 @@ class RestoreViewController: KeyboardAwareViewController { let viewController = RestoreNonStandardModule.viewController(sourceViewController: self, returnViewController: returnViewController) navigationController?.pushViewController(viewController, animated: true) } - } extension RestoreViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections: [SectionProtocol] = [ Section( - id: "margin", - headerState: .margin(height: .margin12) + id: "margin", + headerState: .margin(height: .margin12) ), Section( - id: "name", - headerState: tableView.sectionHeader(text: "create_wallet.name".localized), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: nameCell, - id: "name", - height: .heightSingleLineCell - ) - ] - ) + id: "name", + headerState: tableView.sectionHeader(text: "create_wallet.name".localized), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: nameCell, + id: "name", + height: .heightSingleLineCell + ), + ] + ), ] if advanced { sections.append( - Section( - id: "restore-type", - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "restore_type", - title: .body("restore.import_by".localized), - value: .subhead1(restoreType.title), - accessoryType: .dropdown, - autoDeselect: true, - isFirst: true, - isLast: true - ) { [weak self] in - self?.onTapRestoreType() - } - ] - ) + Section( + id: "restore-type", + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( + id: "restore_type", + title: .body("restore.import_by".localized), + value: .subhead1(restoreType.title), + accessoryType: .dropdown, + autoDeselect: true, + isFirst: true, + isLast: true + ) { [weak self] in + self?.onTapRestoreType() + }, + ] + ) ) } switch restoreType { case .mnemonic: sections.append( - Section( + Section( + id: "mnemonic-input", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: mnemonicInputCell, id: "mnemonic-input", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: mnemonicInputCell, - id: "mnemonic-input", - dynamicHeight: { [weak self] width in - self?.mnemonicInputCell.cellHeight(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: mnemonicCautionCell, - id: "mnemonic-caution", - dynamicHeight: { [weak self] width in - self?.mnemonicCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + dynamicHeight: { [weak self] width in + self?.mnemonicInputCell.cellHeight(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: mnemonicCautionCell, + id: "mnemonic-caution", + dynamicHeight: { [weak self] width in + self?.mnemonicCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ) ) if advanced { let advancedSections: [SectionProtocol] = [ Section( - id: "wordlist-passphrase-toggle", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: wordListCell, - id: "word-list", - height: .heightCell48, - autoDeselect: true, - action: { [weak self] in - self?.openWordListSelector() - } - ), - StaticRow( - cell: passphraseToggleCell, - id: "passphrase-toggle", - height: .heightCell48 - ) - ] + id: "wordlist-passphrase-toggle", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: wordListCell, + id: "word-list", + height: .heightCell48, + autoDeselect: true, + action: { [weak self] in + self?.openWordListSelector() + } + ), + StaticRow( + cell: passphraseToggleCell, + id: "passphrase-toggle", + height: .heightCell48 + ), + ] ), Section( - id: "passphrase", - footerState: inputsVisible ? .margin(height: .margin32) : .margin(height: 0), - rows: [ - StaticRow( - cell: passphraseCell, - id: "passphrase", - height: inputsVisible ? .heightSingleLineCell : 0 - ), - StaticRow( - cell: passphraseCautionCell, - id: "passphrase-caution", - dynamicHeight: { [weak self] width in - self?.passphraseCautionCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: passphraseDescriptionCell, - id: "passphrase-description", - dynamicHeight: { [weak self] width in - self.flatMap { $0.inputsVisible ? $0.passphraseDescriptionCell.height(containerWidth: width) : 0 } ?? 0 - } - ) - ] + id: "passphrase", + footerState: inputsVisible ? .margin(height: .margin32) : .margin(height: 0), + rows: [ + StaticRow( + cell: passphraseCell, + id: "passphrase", + height: inputsVisible ? .heightSingleLineCell : 0 + ), + StaticRow( + cell: passphraseCautionCell, + id: "passphrase-caution", + dynamicHeight: { [weak self] width in + self?.passphraseCautionCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: passphraseDescriptionCell, + id: "passphrase-description", + dynamicHeight: { [weak self] width in + self.flatMap { $0.inputsVisible ? $0.passphraseDescriptionCell.height(containerWidth: width) : 0 } ?? 0 + } + ), + ] ), Section( - id: "non-standard-restore", - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "non-standard_restore", - title: .body("restore.non_standard_import".localized), - accessoryType: .disclosure, - autoDeselect: true, - isFirst: true, - isLast: true, - action: { [weak self] in - self?.onTapNonStandardRestore() - } - ) - ] - ) + id: "non-standard-restore", + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( + id: "non-standard_restore", + title: .body("restore.non_standard_import".localized), + accessoryType: .disclosure, + autoDeselect: true, + isFirst: true, + isLast: true, + action: { [weak self] in + self?.onTapNonStandardRestore() + } + ), + ] + ), ] sections.append(contentsOf: advancedSections) } case .privateKey: sections.append( - Section( + Section( + id: "private-key-input", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: privateKeyInputCell, id: "private-key-input", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: privateKeyInputCell, - id: "private-key-input", - dynamicHeight: { [weak self] width in - self?.privateKeyInputCell.cellHeight(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: privateKeyCautionCell, - id: "private-key-caution", - dynamicHeight: { [weak self] width in - self?.privateKeyCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + dynamicHeight: { [weak self] width in + self?.privateKeyInputCell.cellHeight(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: privateKeyCautionCell, + id: "private-key-caution", + dynamicHeight: { [weak self] width in + self?.privateKeyCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ) ) } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewModel.swift index 993fe86b6c..00f5ffa997 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/Restore/RestoreViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift protocol IRestoreSubViewModel: AnyObject { func resolveAccountType() -> AccountType? @@ -28,11 +28,9 @@ class RestoreViewModel { case .privateKey: return privateKeyViewModel } } - } extension RestoreViewModel { - var restoreTypeDriver: Driver { restoreTypeRelay.asDriver() } @@ -63,11 +61,9 @@ extension RestoreViewModel { proceedRelay.accept((service.resolvedName, accountType)) } } - } extension RestoreViewModel { - enum RestoreType: CaseIterable { case mnemonic case privateKey @@ -79,5 +75,4 @@ extension RestoreViewModel { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudModule.swift index 7a8d42d452..2271658a12 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudModule.swift @@ -1,13 +1,12 @@ -import UIKit -import RxSwift import MarketKit +import RxSwift +import UIKit struct RestoreCloudModule { - static func viewController(returnViewController: UIViewController?) -> UIViewController { let service = RestoreCloudService( - cloudAccountBackupManager: App.shared.cloudBackupManager, - accountManager: App.shared.accountManager + cloudAccountBackupManager: App.shared.cloudBackupManager, + accountManager: App.shared.accountManager ) let viewModel = RestoreCloudViewModel(service: service) return RestoreCloudViewController(viewModel: viewModel, returnViewController: returnViewController) @@ -35,7 +34,6 @@ struct RestoreCloudModule { let isFileBackedUp: Bool let showSelectCoins: Bool } - } extension RestoreCloudModule { @@ -45,4 +43,4 @@ extension RestoreCloudModule { case invalidPassword case invalidBackup } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewController.swift index 2d2fbf8531..a607d59004 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewController.swift @@ -1,9 +1,9 @@ import Combine -import Foundation -import UIKit import ComponentKit +import Foundation import SectionsTableView import ThemeKit +import UIKit class RestoreCloudViewController: ThemeViewController { private let viewModel: RestoreCloudViewModel @@ -27,7 +27,8 @@ class RestoreCloudViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -57,30 +58,30 @@ class RestoreCloudViewController: ThemeViewController { emptyView.text = "restore.cloud.empty".localized viewModel.$walletViewItem - .receive(on: DispatchQueue.main) - .sink { [weak self] viewItem in - self?.sync(type: .wallet, viewItem: viewItem) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] viewItem in + self?.sync(type: .wallet, viewItem: viewItem) + } + .store(in: &cancellables) viewModel.$fullBackupViewItem - .receive(on: DispatchQueue.main) - .sink { [weak self] viewItem in - self?.sync(type: .full, viewItem: viewItem) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] viewItem in + self?.sync(type: .full, viewItem: viewItem) + } + .store(in: &cancellables) viewModel.restorePublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.restore(item: $0) - }.store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.restore(item: $0) + }.store(in: &cancellables) viewModel.deleteItemCompletedPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.deleteBackupCompleted(successful: $0) - }.store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.deleteBackupCompleted(successful: $0) + }.store(in: &cancellables) tableView.buildSections() } @@ -120,9 +121,9 @@ class RestoreCloudViewController: ThemeViewController { private func deleteRowAction(id: String) -> RowAction { RowAction(pattern: .icon( - image: UIImage(named: "circle_minus_shifted_24"), - background: UIColor(red: 0, green: 0, blue: 0, alpha: 0) - ), action: { [weak self] cell in + image: UIImage(named: "circle_minus_shifted_24"), + background: UIColor(red: 0, green: 0, blue: 0, alpha: 0) + ), action: { [weak self] _ in self?.viewModel.remove(id: id) }) } @@ -131,13 +132,13 @@ class RestoreCloudViewController: ThemeViewController { let rowAction = deleteRowAction(id: viewItem.uniqueId) return tableView.universalRow62( - id: viewItem.uniqueId, - title: .body(viewItem.name), - description: .subhead2(viewItem.description), - accessoryType: .disclosure, - rowActionProvider: { [ rowAction ] }, - isFirst: rowInfo.isFirst, - isLast: rowInfo.isLast + id: viewItem.uniqueId, + title: .body(viewItem.name), + description: .subhead2(viewItem.description), + accessoryType: .disclosure, + rowActionProvider: { [rowAction] }, + isFirst: rowInfo.isFirst, + isLast: rowInfo.isLast ) { [weak self] in self?.viewModel.didTap(id: viewItem.uniqueId) } @@ -146,43 +147,40 @@ class RestoreCloudViewController: ThemeViewController { private func section(id: String, headerTitle: String? = nil, viewItems: [RestoreCloudViewModel.BackupViewItem]) -> SectionProtocol { let title = headerTitle ?? "" return Section(id: id, - headerState: title.isEmpty ? .margin(height: 0) : tableView.sectionHeader(text: title), - footerState: .margin(height: 24), - rows: viewItems.enumerated().map { index, viewItem in row(viewItem: viewItem, rowInfo: RowInfo(index: index, count: viewItems.count)) } - ) + headerState: title.isEmpty ? .margin(height: 0) : tableView.sectionHeader(text: title), + footerState: .margin(height: 24), + rows: viewItems.enumerated().map { index, viewItem in row(viewItem: viewItem, rowInfo: RowInfo(index: index, count: viewItems.count)) }) } private var descriptionSection: SectionProtocol { Section( - id: "description", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.descriptionRow( - id: "description", - text: "restore.cloud.description".localized, - font: .subhead2, - textColor: .themeGray, - ignoreBottomMargin: true - ) - ] + id: "description", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.descriptionRow( + id: "description", + text: "restore.cloud.description".localized, + font: .subhead2, + textColor: .themeGray, + ignoreBottomMargin: true + ), + ] ) } - } extension RestoreCloudViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { guard !walletViewItem.isEmpty || !fullBackupViewItem.isEmpty else { return [] } - var sections = [ descriptionSection ] + var sections = [descriptionSection] if !walletViewItem.notImported.isEmpty { sections.append( - section(id: "not_imported", headerTitle: "restore.cloud.wallets".localized, viewItems: viewModel.walletViewItem.notImported) + section(id: "not_imported", headerTitle: "restore.cloud.wallets".localized, viewItems: viewModel.walletViewItem.notImported) ) } @@ -200,5 +198,4 @@ extension RestoreCloudViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewModel.swift index 252a418c9f..b517e49f6e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCloud/RestoreCloudViewModel.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation class RestoreCloudViewModel { private let service: RestoreCloudService @@ -13,12 +13,12 @@ class RestoreCloudViewModel { self.service = service service.$oneWalletItems - .sink { [weak self] in self?.sync(type: .wallet, items: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(type: .wallet, items: $0) } + .store(in: &cancellables) service.$fullBackupItems - .sink { [weak self] in self?.sync(type: .full, items: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(type: .full, items: $0) } + .store(in: &cancellables) sync(type: .wallet, items: service.oneWalletItems) sync(type: .full, items: service.fullBackupItems) @@ -47,11 +47,9 @@ class RestoreCloudViewModel { let description = item.source.timestamp.map { DateHelper.instance.formatFullTime(from: Date(timeIntervalSince1970: $0)) } ?? "----" return BackupViewItem(uniqueId: item.source.id, name: item.name, description: description) } - } extension RestoreCloudViewModel { - var restorePublisher: AnyPublisher { restoreSubject.eraseToAnyPublisher() } @@ -69,11 +67,10 @@ extension RestoreCloudViewModel { restoreSubject.send(BackupModule.NamedSource(name: item.name, source: item.source)) } - if let item = service.fullBackupItems.first(where: { item in item.source.id == id}) { + if let item = service.fullBackupItems.first(where: { item in item.source.id == id }) { restoreSubject.send(BackupModule.NamedSource(name: item.name, source: item.source)) } } - } extension RestoreCloudViewModel { @@ -98,5 +95,4 @@ extension RestoreCloudViewModel { notImported.isEmpty && imported.isEmpty } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewController.swift index ed2f135ac3..7f83ba028e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewController.swift @@ -23,6 +23,7 @@ class RestoreFileConfigurationViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } + @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -87,17 +88,17 @@ class RestoreFileConfigurationViewController: KeyboardAwareViewController { private func showMergeAlert() { let viewController = BottomSheetModule.viewController( - image: .warning, - title: "alert.notice".localized, - items: [ - .highlightedDescription(text: "backup_app.restore.notice.description".localized), - ], - buttons: [ - .init(style: .red, title: "backup_app.restore.notice.merge".localized, actionType: .afterClose) { [weak self] in - self?.viewModel.restore() - }, - .init(style: .transparent, title: "button.cancel".localized, actionType: .afterClose), - ] + image: .warning, + title: "alert.notice".localized, + items: [ + .highlightedDescription(text: "backup_app.restore.notice.description".localized), + ], + buttons: [ + .init(style: .red, title: "backup_app.restore.notice.merge".localized, actionType: .afterClose) { [weak self] in + self?.viewModel.restore() + }, + .init(style: .transparent, title: "button.cancel".localized, actionType: .afterClose), + ] ) present(viewController, animated: true) @@ -118,19 +119,19 @@ class RestoreFileConfigurationViewController: KeyboardAwareViewController { private func row(item: BackupAppModule.Item, rowInfo: RowInfo) -> RowProtocol { if let description = item.description { return tableView.universalRow62( - id: item.title, - title: .body(item.title), - description: .subhead2(description), - isFirst: rowInfo.isFirst, - isLast: rowInfo.isLast + id: item.title, + title: .body(item.title), + description: .subhead2(description), + isFirst: rowInfo.isFirst, + isLast: rowInfo.isLast ) } else { return tableView.universalRow48( - id: item.title, - title: .body(item.title), - value: .subhead1(item.value, color: .themeGray), - isFirst: rowInfo.isFirst, - isLast: rowInfo.isLast + id: item.title, + title: .body(item.title), + value: .subhead1(item.value, color: .themeGray), + isFirst: rowInfo.isFirst, + isLast: rowInfo.isLast ) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewModel.swift index e7e96509a5..76474e7ceb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestoreFileConfiguration/RestoreFileConfigurationViewModel.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation class RestoreFileConfigurationViewModel { private let cloudBackupManager: CloudBackupManager @@ -32,10 +32,10 @@ class RestoreFileConfigurationViewModel { let description = alertSubtitle ?? account.type.detailedDescription return BackupAppModule.AccountItem( - accountId: account.id, - name: account.name, - description: description, - cautionType: cautionType + accountId: account.id, + name: account.name, + description: description, + cautionType: cautionType ) } } @@ -53,13 +53,13 @@ extension RestoreFileConfigurationViewModel { let contactAddressCount = rawBackup.contacts.count let watchAccounts = rawBackup .accounts - .filter { $0.account.watchAccount } + .filter(\.account.watchAccount) return BackupAppModule.items( - watchAccountCount: watchAccounts.count, - watchlistCount: rawBackup.watchlistIds.count, - contactAddressCount: contactAddressCount, - blockchainSourcesCount: rawBackup.customSyncSources.count + watchAccountCount: watchAccounts.count, + watchlistCount: rawBackup.watchlistIds.count, + contactAddressCount: contactAddressCount, + blockchainSourcesCount: rawBackup.customSyncSources.count ) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseModule.swift index 37d4c5f554..30a36f6e6c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseModule.swift @@ -2,16 +2,15 @@ import Foundation import UIKit class RestorePassphraseModule { - static func viewController(item: BackupModule.NamedSource, returnViewController: UIViewController?) -> UIViewController { let service = RestorePassphraseService( - iCloudManager: App.shared.cloudBackupManager, - appBackupProvider: App.shared.appBackupProvider, - accountFactory: App.shared.accountFactory, - accountManager: App.shared.accountManager, - walletManager: App.shared.walletManager, - restoreSettingsManager: App.shared.restoreSettingsManager, - restoredBackup: item + iCloudManager: App.shared.cloudBackupManager, + appBackupProvider: App.shared.appBackupProvider, + accountFactory: App.shared.accountFactory, + accountManager: App.shared.accountManager, + walletManager: App.shared.walletManager, + restoreSettingsManager: App.shared.restoreSettingsManager, + restoredBackup: item ) let viewModel = RestorePassphraseViewModel(service: service) let controller = RestorePassphraseViewController(viewModel: viewModel, returnViewController: returnViewController) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseService.swift index 012c7434da..dc05d91fbf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseService.swift @@ -32,7 +32,7 @@ extension RestorePassphraseService { switch restoredBackup.source { case let .wallet(walletBackup): let rawBackup = try appBackupProvider.decrypt(walletBackup: walletBackup, name: restoredBackup.name, passphrase: passphrase) - if walletBackup.version == 2 { // in 2th version we use enabled_wallets and just restore wallet. + if walletBackup.version == 2 { // in 2th version we use enabled_wallets and just restore wallet. appBackupProvider.restore(raws: [rawBackup]) } switch rawBackup.account.type { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseViewController.swift index 48b7a9fa23..7e39467b73 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreFile/RestorePassphrase/RestorePassphraseViewController.swift @@ -30,6 +30,7 @@ class RestorePassphraseViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } + @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintCell.swift index 9f8d788015..42abc21d7f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintCell.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class RestoreMnemonicHintCell: UICollectionViewCell { private let button = SecondaryButton() - private var onTap: (() -> ())? + private var onTap: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) @@ -20,7 +20,8 @@ class RestoreMnemonicHintCell: UICollectionViewCell { button.addTarget(self, action: #selector(onTapButton), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -28,18 +29,15 @@ class RestoreMnemonicHintCell: UICollectionViewCell { onTap?() } - func bind(word: String, onTap: @escaping () -> ()) { + func bind(word: String, onTap: @escaping () -> Void) { button.setTitle(word, for: .normal) self.onTap = onTap } - } extension RestoreMnemonicHintCell { - static func size(word: String) -> CGSize { CGSize(width: SecondaryButton.width(title: word, style: .default, hasImage: false), height: .heightSingleLineCell) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintView.swift index 954e004068..36e45aa41f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicHintView.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import ComponentKit import AlignedCollectionViewFlowLayout +import ComponentKit +import SnapKit +import ThemeKit +import UIKit class RestoreMnemonicHintView: UIView { private static let horizontalPadding: CGFloat = .margin16 @@ -13,7 +13,7 @@ class RestoreMnemonicHintView: UIView { private let emptyView = UIImageView() private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: AlignedCollectionViewFlowLayout(horizontalAlignment: .leading)) - var onSelectWord: ((String) -> ())? + var onSelectWord: ((String) -> Void)? init() { super.init(frame: .zero) @@ -56,14 +56,13 @@ class RestoreMnemonicHintView: UIView { collectionView.register(RestoreMnemonicHintCell.self, forCellWithReuseIdentifier: String(describing: RestoreMnemonicHintCell.self)) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension RestoreMnemonicHintView { - func set(words: [String]) { self.words = words @@ -71,24 +70,20 @@ extension RestoreMnemonicHintView { collectionView.reloadData() collectionView.layoutIfNeeded() } - } extension RestoreMnemonicHintView: UICollectionViewDataSource { - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + public func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { words.count } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: RestoreMnemonicHintCell.self), for: indexPath) } - } extension RestoreMnemonicHintView: UICollectionViewDelegate { - - public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + public func collectionView(_: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? RestoreMnemonicHintCell { let word = words[indexPath.item] cell.bind(word: word) { [weak self] in @@ -96,17 +91,14 @@ extension RestoreMnemonicHintView: UICollectionViewDelegate { } } } - } extension RestoreMnemonicHintView: UICollectionViewDelegateFlowLayout { - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { RestoreMnemonicHintCell.size(word: words[indexPath.item]) } - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { Self.itemSpacing } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicService.swift index 9705111268..3b80cea060 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicService.swift @@ -1,7 +1,7 @@ import Foundation import HdWalletKit -import RxSwift import RxRelay +import RxSwift class RestoreMnemonicService { private let languageManager: LanguageManager @@ -38,11 +38,9 @@ class RestoreMnemonicService { case .portuguese: return "pt" } } - } extension RestoreMnemonicService { - var wordListLanguageObservable: Observable { wordListLanguageRelay.asObservable() } @@ -113,16 +111,14 @@ extension RestoreMnemonicService { } return .mnemonic( - words: words.map { $0.decomposedStringWithCompatibilityMapping }, - salt: passphrase.decomposedStringWithCompatibilityMapping, - bip39Compliant: true + words: words.map(\.decomposedStringWithCompatibilityMapping), + salt: passphrase.decomposedStringWithCompatibilityMapping, + bip39Compliant: true ) } - } extension RestoreMnemonicService { - enum WordItemType { case correct case incorrect @@ -142,5 +138,4 @@ extension RestoreMnemonicService { enum ErrorList: Error { case errors([Error]) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicViewModel.swift index afb7787103..8009caa93e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonic/RestoreMnemonicViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import HdWalletKit +import RxCocoa +import RxRelay +import RxSwift class RestoreMnemonicViewModel { private let service: RestoreMnemonicService @@ -50,11 +50,9 @@ class RestoreMnemonicViewModel { private var cursorItem: RestoreMnemonicService.WordItem? { service.items.first { hasCursor(item: $0) } } - } extension RestoreMnemonicViewModel { - var possibleWordsDriver: Driver<[String]> { possibleWordsRelay.asDriver() } @@ -111,9 +109,9 @@ extension RestoreMnemonicViewModel { } } - invalidRangesRelay.accept(nonCursorInvalidItems.map { $0.range }) + invalidRangesRelay.accept(nonCursorInvalidItems.map(\.range)) - if let cursorItem = cursorItem { + if let cursorItem { let possibleWords = service.possibleWords(string: cursorItem.word) possibleWordsRelay.accept(possibleWords) } else { @@ -122,7 +120,7 @@ extension RestoreMnemonicViewModel { } func onSelect(word: String) { - guard let cursorItem = cursorItem else { + guard let cursorItem else { return } @@ -138,23 +136,21 @@ extension RestoreMnemonicViewModel { service.passphrase = passphrase clearCautions() } - } extension RestoreMnemonicViewModel: IRestoreSubViewModel { - func resolveAccountType() -> AccountType? { mnemonicCautionRelay.accept(nil) passphraseCautionRelay.accept(nil) guard service.items.allSatisfy({ $0.type == .correct }) else { - invalidRangesRelay.accept(service.items.filter { $0.type != .correct }.map { $0.range }) + invalidRangesRelay.accept(service.items.filter { $0.type != .correct }.map(\.range)) return nil } do { - return try service.accountType(words: service.items.map { $0.word }) - } catch RestoreMnemonicService.ErrorList.errors(let errors) { + return try service.accountType(words: service.items.map(\.word)) + } catch let RestoreMnemonicService.ErrorList.errors(errors) { errors.forEach { error in if case RestoreMnemonicService.RestoreError.emptyPassphrase = error { passphraseCautionRelay.accept(Caution(text: "restore.error.empty_passphrase".localized, type: .error)) @@ -168,7 +164,5 @@ extension RestoreMnemonicViewModel: IRestoreSubViewModel { } } - func clear() { - } - + func clear() {} } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardService.swift index f64f5a9aa5..f81720753a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardService.swift @@ -1,7 +1,7 @@ import Foundation import HdWalletKit -import RxSwift import RxRelay +import RxSwift class RestoreMnemonicNonStandardService { private let languageManager: LanguageManager @@ -38,11 +38,9 @@ class RestoreMnemonicNonStandardService { case .portuguese: return "pt" } } - } extension RestoreMnemonicNonStandardService { - var wordListLanguageObservable: Observable { wordListLanguageRelay.asObservable() } @@ -114,11 +112,9 @@ extension RestoreMnemonicNonStandardService { return .mnemonic(words: words, salt: passphrase, bip39Compliant: false) } - } extension RestoreMnemonicNonStandardService { - enum WordItemType { case correct case incorrect @@ -138,5 +134,4 @@ extension RestoreMnemonicNonStandardService { enum ErrorList: Error { case errors([Error]) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardViewModel.swift index 50c21f30e5..bb1bd1e16c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreMnemonicNonStandard/RestoreMnemonicNonStandardViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import HdWalletKit +import RxCocoa +import RxRelay +import RxSwift class RestoreMnemonicNonStandardViewModel { private let service: RestoreMnemonicNonStandardService @@ -50,11 +50,9 @@ class RestoreMnemonicNonStandardViewModel { private var cursorItem: RestoreMnemonicNonStandardService.WordItem? { service.items.first { hasCursor(item: $0) } } - } extension RestoreMnemonicNonStandardViewModel { - var possibleWordsDriver: Driver<[String]> { possibleWordsRelay.asDriver() } @@ -111,9 +109,9 @@ extension RestoreMnemonicNonStandardViewModel { } } - invalidRangesRelay.accept(nonCursorInvalidItems.map { $0.range }) + invalidRangesRelay.accept(nonCursorInvalidItems.map(\.range)) - if let cursorItem = cursorItem { + if let cursorItem { let possibleWords = service.possibleWords(string: cursorItem.word) possibleWordsRelay.accept(possibleWords) } else { @@ -122,7 +120,7 @@ extension RestoreMnemonicNonStandardViewModel { } func onSelect(word: String) { - guard let cursorItem = cursorItem else { + guard let cursorItem else { return } @@ -144,13 +142,13 @@ extension RestoreMnemonicNonStandardViewModel { passphraseCautionRelay.accept(nil) guard service.items.allSatisfy({ $0.type == .correct }) else { - invalidRangesRelay.accept(service.items.filter { $0.type != .correct }.map { $0.range }) + invalidRangesRelay.accept(service.items.filter { $0.type != .correct }.map(\.range)) return nil } do { - return try service.accountType(words: service.items.map { $0.word }) - } catch RestoreMnemonicNonStandardService.ErrorList.errors(let errors) { + return try service.accountType(words: service.items.map(\.word)) + } catch let RestoreMnemonicNonStandardService.ErrorList.errors(errors) { errors.forEach { error in if case RestoreMnemonicNonStandardService.RestoreError.emptyPassphrase = error { passphraseCautionRelay.accept(Caution(text: "restore.error.empty_passphrase".localized, type: .error)) @@ -164,7 +162,5 @@ extension RestoreMnemonicNonStandardViewModel { } } - func clear() { - } - + func clear() {} } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardModule.swift index 8ffd00a5e3..f524b11b06 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardModule.swift @@ -1,9 +1,8 @@ -import UIKit import ThemeKit +import UIKit struct RestoreNonStandardModule { - - static func viewController(sourceViewController: UIViewController?, returnViewController: UIViewController? = nil) -> UIViewController { + static func viewController(sourceViewController _: UIViewController?, returnViewController: UIViewController? = nil) -> UIViewController { let mnemonicService = RestoreMnemonicNonStandardService(languageManager: LanguageManager.shared) let mnemonicViewModel = RestoreMnemonicNonStandardViewModel(service: mnemonicService) @@ -11,12 +10,11 @@ struct RestoreNonStandardModule { let viewModel = RestoreNonStandardViewModel(service: service, mnemonicViewModel: mnemonicViewModel) let viewController = RestoreNonStandardViewController( - viewModel: viewModel, - mnemonicViewModel: mnemonicViewModel, - returnViewController: returnViewController + viewModel: viewModel, + mnemonicViewModel: mnemonicViewModel, + returnViewController: returnViewController ) return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewController.swift index 90933ac923..dafb2abfce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewController.swift @@ -1,12 +1,12 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import RxSwift import RxCocoa +import RxSwift import SectionsTableView import SnapKit -import ComponentKit +import ThemeKit import UIExtensions +import UIKit class RestoreNonStandardViewController: KeyboardAwareViewController { private let viewModel: RestoreNonStandardViewModel @@ -44,7 +44,8 @@ class RestoreNonStandardViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: hintView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -93,16 +94,16 @@ class RestoreNonStandardViewController: KeyboardAwareViewController { passphraseToggleCell.set(backgroundStyle: .lawrence, isFirst: false, isLast: true) CellBuilderNew.buildStatic( - cell: passphraseToggleCell, - rootElement: .hStack( - tableView.universalImage24Elements( - image: .local(UIImage(named: "key_phrase_24")?.withTintColor(.themeGray)), - title: .body("restore.passphrase".localized), - accessoryType: .switch { [weak self] in - self?.mnemonicViewModel.onTogglePassphrase(isOn: $0) - } - ) + cell: passphraseToggleCell, + rootElement: .hStack( + tableView.universalImage24Elements( + image: .local(UIImage(named: "key_phrase_24")?.withTintColor(.themeGray)), + title: .body("restore.passphrase".localized), + accessoryType: .switch { [weak self] in + self?.mnemonicViewModel.onTogglePassphrase(isOn: $0) + } ) + ) ) passphraseCell.set(textSecure: true) @@ -174,15 +175,15 @@ class RestoreNonStandardViewController: KeyboardAwareViewController { private func syncWordListLanguageCell(wordListLanguage: String) { CellBuilderNew.buildStatic( - cell: wordListCell, - rootElement: .hStack( - tableView.universalImage24Elements( - image: .local(UIImage(named: "globe_24")?.withTintColor(.themeGray)), - title: .body("create_wallet.word_list".localized), - value: .subhead1(wordListLanguage, color: .themeGray), - accessoryType: .dropdown - ) + cell: wordListCell, + rootElement: .hStack( + tableView.universalImage24Elements( + image: .local(UIImage(named: "globe_24")?.withTintColor(.themeGray)), + title: .body("create_wallet.word_list".localized), + value: .subhead1(wordListLanguage, color: .themeGray), + accessoryType: .dropdown ) + ) ) mnemonicInputCell.set(text: mnemonicInputCell.textView.text) @@ -215,117 +216,114 @@ class RestoreNonStandardViewController: KeyboardAwareViewController { tableView.beginUpdates() tableView.endUpdates() } - } extension RestoreNonStandardViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { let descriptionText = "restore.non_standard_import.description".localized(AppConfig.appName, AppConfig.appName) var sections: [SectionProtocol] = [ Section( - id: "description", - headerState: .margin(height: 3), - footerState: .margin(height: .margin32), - rows: [ - Row( - id: "description", - dynamicHeight: { containerWidth in - DescriptionCell.height(containerWidth: containerWidth, text: descriptionText, font: .subhead2, ignoreBottomMargin: true) - }, - bind: { cell, _ in - cell.label.text = descriptionText - cell.label.font = .subhead2 - cell.label.textColor = .themeGray - } - ) - ] + id: "description", + headerState: .margin(height: 3), + footerState: .margin(height: .margin32), + rows: [ + Row( + id: "description", + dynamicHeight: { containerWidth in + DescriptionCell.height(containerWidth: containerWidth, text: descriptionText, font: .subhead2, ignoreBottomMargin: true) + }, + bind: { cell, _ in + cell.label.text = descriptionText + cell.label.font = .subhead2 + cell.label.textColor = .themeGray + } + ), + ] ), Section( - id: "name", - headerState: tableView.sectionHeader(text: "create_wallet.name".localized), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: nameCell, - id: "name", - height: .heightSingleLineCell - ) - ] - ) + id: "name", + headerState: tableView.sectionHeader(text: "create_wallet.name".localized), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: nameCell, + id: "name", + height: .heightSingleLineCell + ), + ] + ), ] let mnemonicSections: [SectionProtocol] = [ Section( - id: "mnemonic-input", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: mnemonicInputCell, - id: "mnemonic-input", - dynamicHeight: { [weak self] width in - self?.mnemonicInputCell.cellHeight(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: mnemonicCautionCell, - id: "mnemonic-caution", - dynamicHeight: { [weak self] width in - self?.mnemonicCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "mnemonic-input", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: mnemonicInputCell, + id: "mnemonic-input", + dynamicHeight: { [weak self] width in + self?.mnemonicInputCell.cellHeight(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: mnemonicCautionCell, + id: "mnemonic-caution", + dynamicHeight: { [weak self] width in + self?.mnemonicCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "wordlist-passphrase-toggle", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: wordListCell, - id: "word-list", - height: .heightCell48, - autoDeselect: true, - action: { [weak self] in - self?.openWordListSelector() - } - ), - StaticRow( - cell: passphraseToggleCell, - id: "passphrase-toggle", - height: .heightCell48 - ) - ] + id: "wordlist-passphrase-toggle", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: wordListCell, + id: "word-list", + height: .heightCell48, + autoDeselect: true, + action: { [weak self] in + self?.openWordListSelector() + } + ), + StaticRow( + cell: passphraseToggleCell, + id: "passphrase-toggle", + height: .heightCell48 + ), + ] ), Section( - id: "passphrase", - footerState: inputsVisible ? .margin(height: .margin24) : .margin(height: 0), - rows: [ - StaticRow( - cell: passphraseCell, - id: "passphrase", - height: inputsVisible ? .heightSingleLineCell : 0 - ), - StaticRow( - cell: passphraseCautionCell, - id: "passphrase-caution", - dynamicHeight: { [weak self] width in - self?.passphraseCautionCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: passphraseDescriptionCell, - id: "passphrase-description", - dynamicHeight: { [weak self] width in - self.flatMap { $0.inputsVisible ? $0.passphraseDescriptionCell.height(containerWidth: width) : 0 } ?? 0 - } - ) - ] - ) + id: "passphrase", + footerState: inputsVisible ? .margin(height: .margin24) : .margin(height: 0), + rows: [ + StaticRow( + cell: passphraseCell, + id: "passphrase", + height: inputsVisible ? .heightSingleLineCell : 0 + ), + StaticRow( + cell: passphraseCautionCell, + id: "passphrase-caution", + dynamicHeight: { [weak self] width in + self?.passphraseCautionCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: passphraseDescriptionCell, + id: "passphrase-description", + dynamicHeight: { [weak self] width in + self.flatMap { $0.inputsVisible ? $0.passphraseDescriptionCell.height(containerWidth: width) : 0 } ?? 0 + } + ), + ] + ), ] sections.append(contentsOf: mnemonicSections) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewModel.swift index 0a8abe750a..f631b8e331 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreNonStandard/RestoreNonStandardViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class RestoreNonStandardViewModel { private let service: RestoreService @@ -13,11 +13,9 @@ class RestoreNonStandardViewModel { self.service = service self.mnemonicViewModel = mnemonicViewModel } - } extension RestoreNonStandardViewModel { - var proceedSignal: Signal<(String, AccountType)> { proceedRelay.asSignal() } @@ -35,5 +33,4 @@ extension RestoreNonStandardViewModel { proceedRelay.accept((service.resolvedName, accountType)) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyService.swift index 85e8555cc0..82825ed3f5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyService.swift @@ -1,9 +1,8 @@ +import EvmKit import Foundation import HdWalletKit -import EvmKit class RestorePrivateKeyService { - func accountType(text: String) throws -> AccountType { let text = text.trimmingCharacters(in: .whitespaces) @@ -25,27 +24,22 @@ class RestorePrivateKeyService { default: throw RestoreError.nonPrivateKey } - } catch { - } + } catch {} do { let privateKey = try Signer.privateKey(string: text) return .evmPrivateKey(data: privateKey) - } catch { - } + } catch {} throw RestoreError.noValidKey } - } extension RestorePrivateKeyService { - enum RestoreError: Error { case emptyText case notSupportedDerivedType case nonPrivateKey case noValidKey } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyViewModel.swift index 2d0a0aa306..f136d7d620 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestorePrivateKey/RestorePrivateKeyViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class RestorePrivateKeyViewModel { private let service: RestorePrivateKeyService @@ -14,11 +14,9 @@ class RestorePrivateKeyViewModel { init(service: RestorePrivateKeyService) { self.service = service } - } extension RestorePrivateKeyViewModel { - var cautionDriver: Driver { cautionRelay.asDriver() } @@ -27,11 +25,9 @@ extension RestorePrivateKeyViewModel { self.text = text cautionRelay.accept(nil) } - } extension RestorePrivateKeyViewModel: IRestoreSubViewModel { - func resolveAccountType() -> AccountType? { cautionRelay.accept(nil) @@ -43,7 +39,5 @@ extension RestorePrivateKeyViewModel: IRestoreSubViewModel { } } - func clear() { - } - + func clear() {} } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectModule.swift index ebd220f473..eb773d4193 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectModule.swift @@ -1,35 +1,33 @@ -import UIKit -import RxSwift import MarketKit +import RxSwift +import UIKit struct RestoreSelectModule { - static func viewController(accountName: String, accountType: AccountType, isManualBackedUp: Bool = true, isFileBackedUp: Bool = false, returnViewController: UIViewController?) -> UIViewController { let (blockchainTokensService, blockchainTokensView) = BlockchainTokensModule.module() let (restoreSettingsService, restoreSettingsView) = RestoreSettingsModule.module() let service = RestoreSelectService( - accountName: accountName, - accountType: accountType, - isManualBackedUp: isManualBackedUp, - isFileBackedUp: isFileBackedUp, - accountFactory: App.shared.accountFactory, - accountManager: App.shared.accountManager, - walletManager: App.shared.walletManager, - evmAccountRestoreStateManager: App.shared.evmAccountRestoreStateManager, - marketKit: App.shared.marketKit, - blockchainTokensService: blockchainTokensService, - restoreSettingsService: restoreSettingsService + accountName: accountName, + accountType: accountType, + isManualBackedUp: isManualBackedUp, + isFileBackedUp: isFileBackedUp, + accountFactory: App.shared.accountFactory, + accountManager: App.shared.accountManager, + walletManager: App.shared.walletManager, + evmAccountRestoreStateManager: App.shared.evmAccountRestoreStateManager, + marketKit: App.shared.marketKit, + blockchainTokensService: blockchainTokensService, + restoreSettingsService: restoreSettingsService ) let viewModel = RestoreSelectViewModel(service: service) return RestoreSelectViewController( - viewModel: viewModel, - blockchainTokensView: blockchainTokensView, - restoreSettingsView: restoreSettingsView, - returnViewController: returnViewController + viewModel: viewModel, + blockchainTokensView: blockchainTokensView, + restoreSettingsView: restoreSettingsView, + returnViewController: returnViewController ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectService.swift index 178a97e42c..726ca634fa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectService.swift @@ -63,7 +63,7 @@ class RestoreSelectService { private func syncInternalItems() { do { - let tokenQueries = BlockchainType.supported.map { $0.nativeTokenQueries }.flatMap { $0 } + let tokenQueries = BlockchainType.supported.map(\.nativeTokenQueries).flatMap { $0 } let allTokens = try marketKit.tokens(queries: tokenQueries) tokens = allTokens.filter { accountType.supports(token: $0) } @@ -91,7 +91,7 @@ class RestoreSelectService { } private func syncState() { - let blockchains = Set(tokens.map { $0.blockchain }) + let blockchains = Set(tokens.map(\.blockchain)) items = blockchains.sorted { $0.type.order < $1.type.order }.map { item(blockchain: $0) } } @@ -162,7 +162,7 @@ extension RestoreSelectService { handleApproveTokens(blockchain: token.blockchain, tokens: [token]) } } else { - blockchainTokensService.approveTokens(blockchain: token.blockchain, tokens: tokens, enabledTokens: tokens.filter { $0.type.isDefault }) + blockchainTokensService.approveTokens(blockchain: token.blockchain, tokens: tokens, enabledTokens: tokens.filter(\.type.isDefault)) } } @@ -208,7 +208,7 @@ extension RestoreSelectService { return } - for blockchainType in Set(enabledTokens.map { $0.blockchainType }) { + for blockchainType in Set(enabledTokens.map(\.blockchainType)) { evmAccountRestoreStateManager.setRestored(account: account, blockchainType: blockchainType) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewController.swift index f6b4037633..9dd78adbc0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewController.swift @@ -1,10 +1,10 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import SectionsTableView -import RxSwift import RxCocoa -import ComponentKit +import RxSwift +import SectionsTableView +import ThemeKit +import UIKit class RestoreSelectViewController: CoinToggleViewController { private let viewModel: RestoreSelectViewModel @@ -22,7 +22,8 @@ class RestoreSelectViewController: CoinToggleViewController { super.init(viewModel: viewModel) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -57,5 +58,4 @@ class RestoreSelectViewController: CoinToggleViewController { @objc private func onTapRightBarButton() { viewModel.onRestore() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewModel.swift index efa30a9f85..a89d33d746 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreSelect/RestoreSelectViewModel.swift @@ -1,7 +1,7 @@ -import UIKit -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift +import UIKit class RestoreSelectViewModel { private let service: RestoreSelectService @@ -9,7 +9,7 @@ class RestoreSelectViewModel { private let viewItemsRelay = BehaviorRelay<[CoinToggleViewModel.ViewItem]>(value: []) private let disableBlockchainRelay = PublishRelay() - private let successRelay = PublishRelay<()>() + private let successRelay = PublishRelay() init(service: RestoreSelectService) { self.service = service @@ -22,24 +22,22 @@ class RestoreSelectViewModel { private func viewItem(item: RestoreSelectService.Item) -> CoinToggleViewModel.ViewItem { CoinToggleViewModel.ViewItem( - uid: item.blockchain.uid, - imageUrl: item.blockchain.type.imageUrl, - placeholderImageName: "placeholder_rectangle_32", - title: item.blockchain.name, - subtitle: item.blockchain.type.description, - badge: nil, - state: .toggleVisible(enabled: item.enabled, hasSettings: item.hasSettings, hasInfo: false) + uid: item.blockchain.uid, + imageUrl: item.blockchain.type.imageUrl, + placeholderImageName: "placeholder_rectangle_32", + title: item.blockchain.name, + subtitle: item.blockchain.type.description, + badge: nil, + state: .toggleVisible(enabled: item.enabled, hasSettings: item.hasSettings, hasInfo: false) ) } private func sync(items: [RestoreSelectService.Item]) { viewItemsRelay.accept(items.map { viewItem(item: $0) }) } - } extension RestoreSelectViewModel: ICoinToggleViewModel { - var viewItemsDriver: Driver<[CoinToggleViewModel.ViewItem]> { viewItemsRelay.asDriver() } @@ -56,16 +54,12 @@ extension RestoreSelectViewModel: ICoinToggleViewModel { service.configure(blockchainUid: uid) } - func onTapInfo(uid: String) { - } - - func onUpdate(filter: String) { - } + func onTapInfo(uid _: String) {} + func onUpdate(filter _: String) {} } extension RestoreSelectViewModel { - var disableBlockchainSignal: Signal { disableBlockchainRelay.asSignal() } @@ -74,7 +68,7 @@ extension RestoreSelectViewModel { service.canRestoreObservable.asDriver(onErrorJustReturn: false) } - var successSignal: Signal<()> { + var successSignal: Signal { successRelay.asSignal() } @@ -82,5 +76,4 @@ extension RestoreSelectViewModel { service.restore() successRelay.accept(()) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsModule.swift index b46bbf524b..715e4f70ac 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsModule.swift @@ -1,5 +1,4 @@ -struct RestoreSettingsModule { - +enum RestoreSettingsModule { static func module() -> (RestoreSettingsService, RestoreSettingsView) { let service = RestoreSettingsService(manager: App.shared.restoreSettingsManager) let viewModel = RestoreSettingsViewModel(service: service) @@ -7,5 +6,4 @@ struct RestoreSettingsModule { return (service, view) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsService.swift index 73d291aea7..3ea03b26b7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsService.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class RestoreSettingsService { private let manager: RestoreSettingsManager @@ -13,11 +13,9 @@ class RestoreSettingsService { init(manager: RestoreSettingsManager) { self.manager = manager } - } extension RestoreSettingsService { - var approveSettingsObservable: Observable { approveSettingsRelay.asObservable() } @@ -33,7 +31,7 @@ extension RestoreSettingsService { func approveSettings(token: Token, account: Account? = nil) { let blockchainType = token.blockchainType - if let account = account, case .created = account.origin { + if let account, case .created = account.origin { var settings = RestoreSettings() for type in blockchainType.restoreSettingTypes { @@ -46,10 +44,10 @@ extension RestoreSettingsService { let existingSettings = account.map { manager.settings(accountId: $0.id, blockchainType: blockchainType) } ?? [:] - if blockchainType.restoreSettingTypes.contains(.birthdayHeight) && existingSettings[.birthdayHeight] == nil { + if blockchainType.restoreSettingTypes.contains(.birthdayHeight), existingSettings[.birthdayHeight] == nil { let request = Request( - token: token, - type: .birthdayHeight + token: token, + type: .birthdayHeight ) requestRelay.accept(request) @@ -82,11 +80,9 @@ extension RestoreSettingsService { func settings(accountId: String, blockchainType: BlockchainType) -> RestoreSettings { manager.settings(accountId: accountId, blockchainType: blockchainType) } - } extension RestoreSettingsService { - struct TokenWithSettings { let token: Token let settings: RestoreSettings @@ -100,5 +96,4 @@ extension RestoreSettingsService { enum RequestType { case birthdayHeight } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsView.swift index e822e92b2e..129eb33dba 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsView.swift @@ -1,14 +1,14 @@ -import UIKit -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift import ThemeKit +import UIKit class RestoreSettingsView { private let viewModel: RestoreSettingsViewModel private let disposeBag = DisposeBag() - var onOpenController: ((UIViewController) -> ())? + var onOpenController: ((UIViewController) -> Void)? init(viewModel: RestoreSettingsViewModel) { self.viewModel = viewModel @@ -28,5 +28,4 @@ class RestoreSettingsView { } onOpenController?(ThemeNavigationController(rootViewController: controller)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsViewModel.swift index 447d308ad8..aaafca2c11 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreSettings/RestoreSettingsViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class RestoreSettingsViewModel { private let service: RestoreSettingsService @@ -25,11 +25,9 @@ class RestoreSettingsViewModel { openBirthdayAlertRelay.accept(request.token) } } - } extension RestoreSettingsViewModel { - var openBirthdayAlertSignal: Signal { openBirthdayAlertRelay.asSignal() } @@ -52,5 +50,4 @@ extension RestoreSettingsViewModel { service.cancel(token: request.token) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionService.swift index 0cea113b83..e3994ae7f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class SendAmountCautionService { private let disposeBag = DisposeBag() @@ -13,10 +13,11 @@ class SendAmountCautionService { setAvailableBalanceService() } } + weak var sendAmountBoundsService: ISendXSendAmountBoundsService? private let amountCautionRelay = BehaviorRelay(value: nil) - private(set) var amountCaution: Caution? = nil { + private(set) var amountCaution: Caution? { didSet { amountCautionRelay.accept(amountCaution) } @@ -30,7 +31,7 @@ class SendAmountCautionService { private func setAvailableBalanceService() { availableBalanceDisposeBag = DisposeBag() - if let availableBalanceService = availableBalanceService { + if let availableBalanceService { subscribe(availableBalanceDisposeBag, availableBalanceService.availableBalanceObservable) { [weak self] _ in self?.sync() } @@ -44,36 +45,35 @@ class SendAmountCautionService { return } if let availableBalance = availableBalanceService?.availableBalance.data, - availableBalance < amount { + availableBalance < amount + { amountCaution = .insufficientBalance(availableBalance: availableBalance) return } if let maximumAmount = sendAmountBoundsService?.maximumSendAmount, - maximumAmount < amount { + maximumAmount < amount + { amountCaution = .maximumAmountExceeded(maximumAmount: maximumAmount) return } if let minimumAmount = sendAmountBoundsService?.minimumSendAmount, - minimumAmount > amount { + minimumAmount > amount + { amountCaution = .tooFewAmount(minimumAmount: minimumAmount) return } amountCaution = nil } - } extension SendAmountCautionService { - var amountCautionObservable: Observable { amountCautionRelay.asObservable() } - } extension SendAmountCautionService { - enum Caution { case insufficientBalance(availableBalance: Decimal) case maximumAmountExceeded(maximumAmount: Decimal) @@ -81,12 +81,10 @@ extension SendAmountCautionService { var value: Decimal { switch self { - case .insufficientBalance(let value): return value - case .maximumAmountExceeded( let value): return value - case .tooFewAmount(let value): return value + case let .insufficientBalance(value): return value + case let .maximumAmountExceeded(value): return value + case let .tooFewAmount(value): return value } } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionViewModel.swift index aa555a9542..3b559e9fc6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountCaution/SendAmountCautionViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift class SendAmountCautionViewModel { private let disposeBag = DisposeBag() @@ -11,7 +11,7 @@ class SendAmountCautionViewModel { private let coinService: CoinService private let amountCautionRelay = BehaviorRelay(value: nil) - private(set) var amountCaution: Caution? = nil { + private(set) var amountCaution: Caution? { didSet { amountCautionRelay.accept(amountCaution) } @@ -28,12 +28,12 @@ class SendAmountCautionViewModel { } private func sync(amountCaution: SendAmountCautionService.Caution?) { - guard let amountCaution = amountCaution else { + guard let amountCaution else { self.amountCaution = nil return } - var amountInfo: AmountInfo? = nil + var amountInfo: AmountInfo? switch switchService.amountType { case .coin: @@ -55,13 +55,10 @@ class SendAmountCautionViewModel { self.amountCaution = Caution(text: "send.amount_error.minimum_amount".localized(amountInfo?.formattedFull ?? ""), type: .error) } } - } extension SendAmountCautionViewModel { - var amountCautionDriver: Driver { amountCautionRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountInput/SendBitcoinAmountInputService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountInput/SendBitcoinAmountInputService.swift index d4231f16a7..969e5de913 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountInput/SendBitcoinAmountInputService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/AmountInput/SendBitcoinAmountInputService.swift @@ -34,13 +34,11 @@ extension SendBitcoinAmountInputService: IAmountInputService { } var balanceObservable: Observable { - guard let availableBalanceService = availableBalanceService else { + guard let availableBalanceService else { return .just(nil) } - return availableBalanceService.availableBalanceObservable.map { - $0.data - } + return availableBalanceService.availableBalanceObservable.map(\.data) } var tokenObservable: Observable { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationModule.swift index 070645bb08..cfe9b168cf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationModule.swift @@ -13,7 +13,6 @@ struct SendConfirmationAmountViewItem: ISendConfirmationViewItemNew { self.receiver = receiver self.isAccount = isAccount } - } struct SendConfirmationFeeViewItem: ISendConfirmationViewItemNew { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationService.swift index e9240f0b82..a8ec99b994 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationService.swift @@ -1,8 +1,8 @@ -import RxSwift -import RxRelay -import RxCocoa -import MarketKit import HsToolKit +import MarketKit +import RxCocoa +import RxRelay +import RxSwift class SendConfirmationService { private var sendDisposeBag = DisposeBag() @@ -24,43 +24,38 @@ class SendConfirmationService { self.token = token self.items = items } - } extension SendConfirmationService { - var stateObservable: Observable { stateRelay.asObservable() } func send() { sendDisposeBag = DisposeBag() - let actionLogger = logger.scoped(with: "\(Int.random(in: 0..<1_000_000))") + let actionLogger = logger.scoped(with: "\(Int.random(in: 0 ..< 1_000_000))") actionLogger.debug("Confirm clicked", save: true) state = .sending sendService - .sendSingle(logger: actionLogger) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] in - actionLogger.debug("Send success", save: true) - self?.state = .sent - }, onError: { [weak self] error in - actionLogger.error("Send failed due to \(String(reflecting: error))", save: true) - self?.state = .failed(error: error) - }) - .disposed(by: sendDisposeBag) + .sendSingle(logger: actionLogger) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] in + actionLogger.debug("Send success", save: true) + self?.state = .sent + }, onError: { [weak self] error in + actionLogger.error("Send failed due to \(String(reflecting: error))", save: true) + self?.state = .failed(error: error) + }) + .disposed(by: sendDisposeBag) } - } extension SendConfirmationService { - enum State { case idle case sending case sent case failed(error: Error) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewController.swift index cfce945345..c0162d318c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import SnapKit -import SectionsTableView +import ComponentKit import RxSwift +import SectionsTableView +import SnapKit import ThemeKit -import ComponentKit +import UIKit class SendConfirmationViewController: ThemeViewController, SectionsDataSource { private let disposeBag = DisposeBag() @@ -21,7 +21,8 @@ class SendConfirmationViewController: ThemeViewController, SectionsDataSource { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -58,7 +59,6 @@ class SendConfirmationViewController: ThemeViewController, SectionsDataSource { subscribe(disposeBag, viewModel.sendingSignal) { HudHelper.instance.show(banner: .sending) } subscribe(disposeBag, viewModel.sendSuccessSignal) { [weak self] in self?.handleSendSuccess() } subscribe(disposeBag, viewModel.sendFailedSignal) { [weak self] in self?.handleSendFailed(error: $0) } - } private func sync(viewItems: [[SendConfirmationViewModel.ViewItem]]) { @@ -88,7 +88,7 @@ class SendConfirmationViewController: ThemeViewController, SectionsDataSource { case let .amount(iconUrl, iconPlaceholderImageName, coinAmount, currencyAmount, type): return CellComponent.amountRow(tableView: tableView, rowInfo: rowInfo, iconUrl: iconUrl, iconPlaceholderImageName: iconPlaceholderImageName, coinAmount: coinAmount, currencyAmount: currencyAmount, type: type) case let .address(title, value, valueTitle, contactAddress): - var onAddToContact: (() -> ())? = nil + var onAddToContact: (() -> Void)? = nil if let contactAddress { onAddToContact = { [weak self] in ContactBookModule.showAddition(contactAddress: contactAddress, parentViewController: self) @@ -99,24 +99,22 @@ class SendConfirmationViewController: ThemeViewController, SectionsDataSource { return CellComponent.valueRow(tableView: tableView, rowInfo: rowInfo, iconName: iconName, title: title, value: value, type: type) } } - } extension SendConfirmationViewController { - func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() viewItems.enumerated().forEach { index, viewItems in sections.append( - Section( - id: "section-\(index)", - headerState: .margin(height: .margin12), - rows: viewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, rowInfo: RowInfo(index: index, isFirst: index == 0, isLast: index == viewItems.count - 1)) - })) + Section( + id: "section-\(index)", + headerState: .margin(height: .margin12), + rows: viewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, rowInfo: RowInfo(index: index, isFirst: index == 0, isLast: index == viewItems.count - 1)) + } + )) } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewModel.swift index 4d13acfbed..ff6b1df18b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Confirmation/SendConfirmationViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class SendConfirmationViewModel { private let disposeBag = DisposeBag() @@ -15,8 +15,8 @@ class SendConfirmationViewModel { } private let sendEnabledRelay = BehaviorRelay(value: false) - private let sendingRelay = PublishRelay<()>() - private let sendSuccessRelay = PublishRelay<()>() + private let sendingRelay = PublishRelay() + private let sendSuccessRelay = PublishRelay() private let sendFailedRelay = PublishRelay() init(service: SendConfirmationService, contactLabelService: ContactLabelService) { @@ -36,75 +36,76 @@ class SendConfirmationViewModel { var secondaryViewItems = [ViewItem]() primaryViewItems.append( - .subhead( - iconName: "arrow_medium_2_up_right_24", - title: "send.confirmation.you_send".localized, - value: service.token.coin.name - ) + .subhead( + iconName: "arrow_medium_2_up_right_24", + title: "send.confirmation.you_send".localized, + value: service.token.coin.name + ) ) service.items.forEach { item in switch item { case let item as SendConfirmationAmountViewItem: primaryViewItems.append( - .amount( - iconUrl: service.token.coin.imageUrl, - iconPlaceholderImageName: service.token.placeholderImageName, - coinAmount: ValueFormatter.instance.formatFull(coinValue: item.coinValue) ?? "n/a".localized, - currencyAmount: item.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, - type: .neutral - ) + .amount( + iconUrl: service.token.coin.imageUrl, + iconPlaceholderImageName: service.token.placeholderImageName, + coinAmount: ValueFormatter.instance.formatFull(coinValue: item.coinValue) ?? "n/a".localized, + currencyAmount: item.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, + type: .neutral + ) ) let contactData = contactLabelService.contactData(for: item.receiver.raw) primaryViewItems.append( - .address( - title: "send.confirmation.to".localized, - value: item.receiver.raw, - valueTitle: item.receiver.title, - contactAddress: contactData.contactAddress - ) + .address( + title: "send.confirmation.to".localized, + value: item.receiver.raw, + valueTitle: item.receiver.title, + contactAddress: contactData.contactAddress + ) ) if let contactName = contactData.name { primaryViewItems.append( - .value( - iconName: nil, - title: "send.confirmation.contact_name".localized, - value: contactName, - type: .regular) + .value( + iconName: nil, + title: "send.confirmation.contact_name".localized, + value: contactName, + type: .regular + ) ) } case let item as SendConfirmationMemoViewItem: primaryViewItems.append( - .value( - iconName: nil, - title: "send.confirmation.memo".localized, - value: item.memo, - type: .regular - ) + .value( + iconName: nil, + title: "send.confirmation.memo".localized, + value: item.memo, + type: .regular + ) ) case let item as SendConfirmationFeeViewItem: let value = [ValueFormatter.instance.formatFull(coinValue: item.coinValue), item.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }] - .compactMap { $0 } - .joined(separator: " | ") + .compactMap { $0 } + .joined(separator: " | ") secondaryViewItems.append( - .value( - iconName: nil, - title: "send.confirmation.fee".localized, - value: value, - type: .regular - ) + .value( + iconName: nil, + title: "send.confirmation.fee".localized, + value: value, + type: .regular + ) ) case let item as SendConfirmationLockUntilViewItem: primaryViewItems.append( - .value( - iconName: "lock_24", - title: "send.confirmation.time_lock".localized, - value: item.lockValue, - type: .regular - ) + .value( + iconName: "lock_24", + title: "send.confirmation.time_lock".localized, + value: item.lockValue, + type: .regular + ) ) default: () @@ -124,16 +125,14 @@ class SendConfirmationViewModel { case .sent: sendEnabledRelay.accept(false) sendSuccessRelay.accept(()) - case .failed(let error): + case let .failed(error): sendEnabledRelay.accept(true) sendFailedRelay.accept(error.smartDescription) } } - } extension SendConfirmationViewModel { - var viewItemDriver: Driver<[[ViewItem]]> { viewItemRelay.asDriver() } @@ -142,11 +141,11 @@ extension SendConfirmationViewModel { sendEnabledRelay.asDriver() } - var sendingSignal: Signal<()> { + var sendingSignal: Signal { sendingRelay.asSignal() } - var sendSuccessSignal: Signal<()> { + var sendSuccessSignal: Signal { sendSuccessRelay.asSignal() } @@ -157,15 +156,13 @@ extension SendConfirmationViewModel { func send() { service.send() } - } -extension SendConfirmationViewModel { +extension SendConfirmationViewModel { enum ViewItem { case subhead(iconName: String, title: String, value: String) case amount(iconUrl: String?, iconPlaceholderImageName: String, coinAmount: String, currencyAmount: String?, type: AmountType) case address(title: String, value: String, valueTitle: String?, contactAddress: ContactAddress?) case value(iconName: String?, title: String, value: String, type: ValueType) } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeService.swift index 5dc1ac5151..98e6712db7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeService.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import RxRelay -import RxCocoa import MarketKit +import RxCocoa +import RxRelay +import RxSwift class SendFeeService { private let scheduler = SerialDispatchQueueScheduler(qos: .userInitiated, internalSerialQueueName: "\(AppConfig.label).send-fee-service") @@ -39,7 +39,7 @@ class SendFeeService { private func setFeeValueService() { feeRateDisposeBag = DisposeBag() - if let feeValueService = feeValueService { + if let feeValueService { subscribe(feeRateDisposeBag, feeValueService.feeStateObservable) { [weak self] in self?.sync(feeState: $0) } @@ -49,8 +49,8 @@ class SendFeeService { private func sync(feeState: DataStatus) { switch feeState { case .loading: state = .loading - case .failed(let error): state = .failed(error) - case .completed(let value): + case let .failed(error): state = .failed(error) + case let .completed(value): fiatService.set(coinAmount: value) } } @@ -65,29 +65,24 @@ class SendFeeService { let secondaryInfo = secondaryInfo ?? fiatService.secondaryAmountInfo switch primaryInfo { - case .amount(let value): + case let .amount(value): state = .completed(State(primaryInfo: amountInfo(value: value), secondaryInfo: secondaryInfo)) - case .amountInfo(let value): + case let .amountInfo(value): let amountInfo = value ?? amountInfo(value: fiatService.coinAmount) state = .completed(State(primaryInfo: amountInfo, secondaryInfo: secondaryInfo)) } } - } extension SendFeeService { - var stateObservable: Observable> { stateRelay.asObservable() } - } extension SendFeeService { - struct State { let primaryInfo: AmountInfo let secondaryInfo: AmountInfo? } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeViewModel.swift index 4ad429086c..90be7b76fe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Fee/SendFeeViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class SendFeeViewModel { private let disposeBag = DisposeBag() @@ -18,7 +18,6 @@ class SendFeeViewModel { subscribe(disposeBag, service.stateObservable) { [weak self] in self?.sync(state: $0) } - } private func sync(state: DataStatus) { @@ -35,7 +34,7 @@ class SendFeeViewModel { spinnerVisibleRelay.accept(false) valueRelay.accept(.error(text: "n/a".localized)) - case .completed(let state): + case let .completed(state): spinnerVisibleRelay.accept(false) firstLoaded = true @@ -47,11 +46,9 @@ class SendFeeViewModel { valueRelay.accept(.regular(text: state.primaryInfo.formattedFull ?? "n/a".localized, secondaryText: state.secondaryInfo?.formattedFull)) } } - } extension SendFeeViewModel: IFeeViewModel { - var valueDriver: Driver { valueRelay.asDriver() } @@ -59,5 +56,4 @@ extension SendFeeViewModel: IFeeViewModel { var spinnerVisibleDriver: Driver { spinnerVisibleRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputCell.swift index eb26bd8988..9b6d20bd07 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import RxSwift +import SnapKit +import ThemeKit +import UIKit class SendMemoInputCell: UITableViewCell { private let disposeBag = DisposeBag() @@ -12,9 +12,9 @@ class SendMemoInputCell: UITableViewCell { private let topInset: CGFloat private var hiddenState: Bool = false - var onChangeHeight: (() -> ())? + var onChangeHeight: (() -> Void)? - init(viewModel: SendMemoInputViewModel, topInset: CGFloat = 0) { // topInset used for make header padding, which may be dynamically collapse + init(viewModel: SendMemoInputViewModel, topInset: CGFloat = 0) { // topInset used for make header padding, which may be dynamically collapse self.viewModel = viewModel self.topInset = topInset @@ -41,7 +41,6 @@ class SendMemoInputCell: UITableViewCell { anInputView.inputPlaceholder = "send.confirmation.memo_placeholder".localized anInputView.font = UIFont.body.with(traits: .traitItalic) - anInputView.onChangeText = { [weak self] in self?.viewModel.change(text: $0) } @@ -54,7 +53,8 @@ class SendMemoInputCell: UITableViewCell { sync(hidden: viewModel.isHidden) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -62,14 +62,11 @@ class SendMemoInputCell: UITableViewCell { hiddenState = hidden onChangeHeight?() } - } extension SendMemoInputCell { - func height(containerWidth: CGFloat) -> CGFloat { let height = anInputView.height(containerWidth: containerWidth) + topInset return hiddenState ? 0 : height } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputService.swift index 436ea4072b..40b8502211 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputService.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift protocol IMemoAvailableService: AnyObject { var isAvailable: Bool { get } @@ -33,7 +33,7 @@ class SendMemoInputService { private func setAvailableService() { availableDisposeBag = DisposeBag() - if let availableService = availableService { + if let availableService { subscribe(availableDisposeBag, availableService.isAvailableObservable) { [weak self] in self?.sync(available: $0) } sync(available: availableService.isAvailable) } @@ -42,11 +42,9 @@ class SendMemoInputService { private func sync(available: Bool) { isAvailable = available } - } extension SendMemoInputService { - var isAvailableObservable: Observable { isAvailableRelay.asObservable() } @@ -62,5 +60,4 @@ extension SendMemoInputService { func isValid(text: String) -> Bool { text.count <= maxSymbols } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputViewModel.swift index 08b4f3299c..06cff38004 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/MemoInput/SendMemoInputViewModel.swift @@ -1,7 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa - +import RxRelay +import RxSwift class SendMemoInputViewModel { private let disposeBag = DisposeBag() @@ -24,11 +23,9 @@ class SendMemoInputViewModel { private func sync(available: Bool) { isHidden = !available } - } extension SendMemoInputViewModel { - var isHiddenDriver: Driver { isHiddenRelay.asDriver() } @@ -40,5 +37,4 @@ extension SendMemoInputViewModel { func isValid(text: String) -> Bool { service.isValid(text: text) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/BaseSendViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/BaseSendViewController.swift index dfd3fab3d6..185a9d4da2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/BaseSendViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/BaseSendViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class BaseSendViewController: ThemeViewController, SectionsDataSource { private let disposeBag = DisposeBag() @@ -36,9 +36,8 @@ class BaseSendViewController: ThemeViewController, SectionsDataSource { availableBalanceViewModel: SendAvailableBalanceViewModel, amountInputViewModel: AmountInputViewModel, amountCautionViewModel: SendAmountCautionViewModel, - recipientViewModel: RecipientAddressViewModel - ) { - + recipientViewModel: RecipientAddressViewModel) + { self.confirmationFactory = confirmationFactory self.feeSettingsFactory = feeSettingsFactory @@ -55,7 +54,8 @@ class BaseSendViewController: ThemeViewController, SectionsDataSource { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -172,11 +172,9 @@ class BaseSendViewController: ThemeViewController, SectionsDataSource { } return sections } - } extension BaseSendViewController { - func didLoad() { tableView.buildSections() isLoaded = true @@ -195,74 +193,73 @@ extension BaseSendViewController { var availableBalanceSection: SectionProtocol { Section( - id: "available-balance", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: availableBalanceCell, - id: "available-balance", - height: availableBalanceCell.cellHeight - ) - ] + id: "available-balance", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: availableBalanceCell, + id: "available-balance", + height: availableBalanceCell.cellHeight + ), + ] ) } var amountSection: SectionProtocol { Section( - id: "amount", - headerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: amountCell, - id: "amount-input", - height: amountCell.cellHeight - ), - StaticRow( - cell: amountCautionCell, - id: "amount-caution", - dynamicHeight: { [weak self] width in - self?.amountCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "amount", + headerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: amountCell, + id: "amount-input", + height: amountCell.cellHeight + ), + StaticRow( + cell: amountCautionCell, + id: "amount-caution", + dynamicHeight: { [weak self] width in + self?.amountCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ) } var recipientSection: SectionProtocol { Section( - id: "recipient", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: recipientCell, - id: "recipient-input", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "recipient-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "recipient", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: recipientCell, + id: "recipient-input", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: recipientCautionCell, + id: "recipient-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ) } var buttonSection: SectionProtocol { Section( - id: "button", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: buttonCell, - id: "button", - height: PrimaryButtonCell.height - ) - ] + id: "button", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: buttonCell, + id: "button", + height: PrimaryButtonCell.height + ), + ] ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/FeeWarning/SendBinanceFeeWarningViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/FeeWarning/SendBinanceFeeWarningViewModel.swift index cc30e05624..bcacb6c29c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/FeeWarning/SendBinanceFeeWarningViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/FeeWarning/SendBinanceFeeWarningViewModel.swift @@ -1,9 +1,8 @@ import MarketKit -import RxRelay import RxCocoa +import RxRelay class SendBinanceFeeWarningViewModel { - private let cautionRelay = BehaviorRelay(value: nil) init(adapter: ISendBinanceAdapter, coinCode: String, feeToken: Token) { @@ -15,13 +14,10 @@ class SendBinanceFeeWarningViewModel { cautionRelay.accept(TitledCaution(title: "fee_settings.errors.insufficient_balance".localized, text: text, type: .error)) } } - } extension SendBinanceFeeWarningViewModel: ITitledCautionViewModel { - var cautionDriver: Driver { cautionRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceFactory.swift index 9b472cf414..13e98dff47 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceFactory.swift @@ -1,6 +1,6 @@ -import UIKit -import MarketKit import HsToolKit +import MarketKit +import UIKit class SendBinanceFactory: BaseSendFactory { private let service: SendBinanceService @@ -41,11 +41,9 @@ class SendBinanceFactory: BaseSendFactory { return viewItems } - } extension SendBinanceFactory: ISendConfirmationFactory { - func confirmationViewController() throws -> UIViewController { let items = try items() @@ -56,5 +54,4 @@ extension SendBinanceFactory: ISendConfirmationFactory { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceService.swift index 68d0a02a88..ddb17105e2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceService.swift @@ -1,8 +1,8 @@ import Foundation +import HsToolKit import MarketKit -import RxSwift import RxRelay -import HsToolKit +import RxSwift class SendBinanceService { private let disposeBag = DisposeBag() @@ -34,10 +34,10 @@ class SendBinanceService { self.mode = mode switch mode { - case .prefilled(let address, let amount): + case let .prefilled(address, amount): addressService.set(text: address) if let amount { addressService.publishAmountRelay.accept(amount) } - case .predefined(let address): addressService.set(text: address) + case let .predefined(address): addressService.set(text: address) case .send: () } @@ -54,8 +54,8 @@ class SendBinanceService { private func syncState() { guard amountCautionService.amountCaution == nil, - !amountService.amount.isZero else { - + !amountService.amount.isZero + else { state = .notReady return } @@ -77,24 +77,20 @@ class SendBinanceService { state = .ready } - } extension SendBinanceService: ISendBaseService { - var stateObservable: Observable { stateRelay.asObservable() } - } extension SendBinanceService: ISendService { - - func sendSingle(logger: Logger) -> Single { + func sendSingle(logger _: Logger) -> Single { let address: Address switch addressService.state { - case .success(let sendAddress): address = sendAddress - case .fetchError(let error): return Single.error(error) + case let .success(sendAddress): address = sendAddress + case let .fetchError(error): return Single.error(error) default: return Single.error(AppError.addressInvalid) } @@ -107,16 +103,14 @@ extension SendBinanceService: ISendService { } return adapter.sendSingle( - amount: amountService.amount, - address: address.raw, - memo: memoService.memo + amount: amountService.amount, + address: address.raw, + memo: memoService.memo ) } - } extension SendBinanceService: ISendXFeeValueService { - var editable: Bool { false } @@ -128,11 +122,9 @@ extension SendBinanceService: ISendXFeeValueService { var feeStateObservable: Observable> { .just(feeState) } - } extension SendBinanceService: IAvailableBalanceService { - var availableBalance: DataStatus { .completed(adapter.availableBalance) } @@ -140,5 +132,4 @@ extension SendBinanceService: IAvailableBalanceService { var availableBalanceObservable: Observable> { .just(availableBalance) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceViewController.swift index 4d23696a31..dd8497c2ef 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Binance/SendBinanceViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class SendBinanceViewController: BaseSendViewController { private let disposeBag = DisposeBag() @@ -23,8 +23,8 @@ class SendBinanceViewController: BaseSendViewController { recipientViewModel: RecipientAddressViewModel, memoViewModel: SendMemoInputViewModel, feeViewModel: SendFeeViewModel, - feeWarningViewModel: ITitledCautionViewModel - ) { + feeWarningViewModel: ITitledCautionViewModel) + { self.feeWarningViewModel = feeWarningViewModel memoCell = SendMemoInputCell(viewModel: memoViewModel) @@ -32,16 +32,17 @@ class SendBinanceViewController: BaseSendViewController { feeCell = FeeCell(viewModel: feeViewModel, title: "fee_settings.fee".localized) super.init( - confirmationFactory: confirmationFactory, - viewModel: viewModel, - availableBalanceViewModel: availableBalanceViewModel, - amountInputViewModel: amountInputViewModel, - amountCautionViewModel: amountCautionViewModel, - recipientViewModel: recipientViewModel + confirmationFactory: confirmationFactory, + viewModel: viewModel, + availableBalanceViewModel: availableBalanceViewModel, + amountInputViewModel: amountInputViewModel, + amountCautionViewModel: amountCautionViewModel, + recipientViewModel: recipientViewModel ) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -62,7 +63,7 @@ class SendBinanceViewController: BaseSendViewController { private func handle(caution: TitledCaution?) { feeCautionCell.isVisible = caution != nil - if let caution = caution { + if let caution { feeCautionCell.bind(caution: caution) } @@ -76,45 +77,45 @@ class SendBinanceViewController: BaseSendViewController { var memoSection: SectionProtocol { Section( - id: "memo", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: memoCell, - id: "memo-input", - height: .heightSingleLineCell - ) - ] + id: "memo", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: memoCell, + id: "memo-input", + height: .heightSingleLineCell + ), + ] ) } var feeSection: SectionProtocol { Section( - id: "fee", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCell, - id: "fee", - height: .heightCell48 - ) - ] + id: "fee", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCell, + id: "fee", + height: .heightCell48 + ), + ] ) } var feeWarningSection: SectionProtocol { Section( - id: "fee-warning", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCautionCell, - id: "fee-warning", - dynamicHeight: { [weak self] containerWidth in - self?.feeCautionCell.cellHeight(containerWidth: containerWidth) ?? 0 - } - ) - ] + id: "fee-warning", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCautionCell, + id: "fee-warning", + dynamicHeight: { [weak self] containerWidth in + self?.feeCautionCell.cellHeight(containerWidth: containerWidth) ?? 0 + } + ), + ] ) } @@ -124,10 +125,9 @@ class SendBinanceViewController: BaseSendViewController { memoSection, feeSection, feeWarningSection, - buttonSection + buttonSection, ]) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeCautionViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeCautionViewModel.swift index 6a99c9daf3..74258e4cd3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeCautionViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeCautionViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class SendFeeCautionViewModel { private let disposeBag = DisposeBag() @@ -39,13 +39,10 @@ class SendFeeCautionViewModel { caution = nil } } - } extension SendFeeCautionViewModel: ITitledCautionViewModel { - var cautionDriver: Driver { cautionRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeSettingsAmountCautionViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeSettingsAmountCautionViewModel.swift index 1e7dc2e343..dd451d8937 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeSettingsAmountCautionViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/FeeWarning/SendFeeSettingsAmountCautionViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift class SendFeeSettingsAmountCautionViewModel { private let disposeBag = DisposeBag() @@ -10,7 +10,7 @@ class SendFeeSettingsAmountCautionViewModel { private let feeToken: Token private let amountCautionRelay = BehaviorRelay(value: nil) - private(set) var amountCaution: TitledCaution? = nil { + private(set) var amountCaution: TitledCaution? { didSet { amountCautionRelay.accept(amountCaution) } @@ -25,7 +25,7 @@ class SendFeeSettingsAmountCautionViewModel { } private func sync(amountCaution: SendAmountCautionService.Caution?) { - guard let amountCaution = amountCaution else { + guard let amountCaution else { self.amountCaution = nil return } @@ -33,19 +33,17 @@ class SendFeeSettingsAmountCautionViewModel { switch amountCaution { case .insufficientBalance: self.amountCaution = TitledCaution( - title: "send.fee_settings.amount_error.balance.title".localized, - text: "send.fee_settings.amount_error.balance".localized(feeToken.coin.code), - type: .error) + title: "send.fee_settings.amount_error.balance.title".localized, + text: "send.fee_settings.amount_error.balance".localized(feeToken.coin.code), + type: .error + ) default: self.amountCaution = nil } } - } extension SendFeeSettingsAmountCautionViewModel { - var amountCautionDriver: Driver { amountCautionRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinAdapterService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinAdapterService.swift index 71c768a717..c0c408d18c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinAdapterService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinAdapterService.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift +import HsToolKit import RxCocoa import RxRelay -import HsToolKit +import RxSwift protocol ISendXFeeValueService: AnyObject { var feeState: DataStatus { get } @@ -62,7 +62,7 @@ class SendBitcoinAdapterService { } let maximumSendAmountRelay = BehaviorRelay(value: nil) - var maximumSendAmount: Decimal? = nil { + var maximumSendAmount: Decimal? { didSet { if maximumSendAmount != oldValue { maximumSendAmountRelay.accept(maximumSendAmount) @@ -71,7 +71,8 @@ class SendBitcoinAdapterService { } init(feeRateService: FeeRateService, amountInputService: IAmountInputService, addressService: AddressService, - inputOutputOrderService: InputOutputOrderService, timeLockService: TimeLockService?, btcBlockchainManager: BtcBlockchainManager, adapter: ISendBitcoinAdapter) { + inputOutputOrderService: InputOutputOrderService, timeLockService: TimeLockService?, btcBlockchainManager: BtcBlockchainManager, adapter: ISendBitcoinAdapter) + { self.feeRateService = feeRateService self.amountInputService = amountInputService self.addressService = addressService @@ -87,7 +88,7 @@ class SendBitcoinAdapterService { self?.sync(updatedFrom: .address) } - if let timeLockService = timeLockService { + if let timeLockService { subscribe(disposeBag, timeLockService.pluginDataObservable) { [weak self] _ in self?.sync(updatedFrom: .pluginData) } @@ -109,15 +110,15 @@ class SendBitcoinAdapterService { switch feeRateStatus { case .loading: - guard !amount.isZero else { // force update fee for bitcoin, when clear amount to zero value + guard !amount.isZero else { // force update fee for bitcoin, when clear amount to zero value feeState = .completed(0) return } feeState = .loading - case .failed(let error): + case let .failed(error): feeState = .failed(error) - case .completed(let _feeRate): + case let .completed(_feeRate): feeRate = _feeRate } @@ -130,7 +131,8 @@ class SendBitcoinAdapterService { self?.feeState = .completed(fee) } if updatedFrom != .amount, - let availableBalance = self?.adapter.availableBalance(feeRate: feeRate, address: address, pluginData: pluginData) { + let availableBalance = self?.adapter.availableBalance(feeRate: feeRate, address: address, pluginData: pluginData) + { self?.availableBalance = .completed(availableBalance) } if updatedFrom == .pluginData { @@ -145,11 +147,9 @@ class SendBitcoinAdapterService { private var pluginData: [UInt8: IBitcoinPluginData] { timeLockService?.pluginData ?? [:] } - } extension SendBitcoinAdapterService: ISendXFeeValueService, IAvailableBalanceService, ISendXSendAmountBoundsService { - var feeStateObservable: Observable> { feeStateRelay.asObservable() } @@ -169,16 +169,14 @@ extension SendBitcoinAdapterService: ISendXFeeValueService, IAvailableBalanceSer func validate(address: String) throws { try adapter.validate(address: address, pluginData: pluginData) } - } extension SendBitcoinAdapterService: ISendService { - func sendSingle(logger: Logger) -> Single { let address: Address switch addressService.state { - case .success(let sendAddress): address = sendAddress - case .fetchError(let error): return Single.error(error) + case let .success(sendAddress): address = sendAddress + case let .fetchError(error): return Single.error(error) default: return Single.error(AppError.addressInvalid) } @@ -192,21 +190,18 @@ extension SendBitcoinAdapterService: ISendService { let sortMode = btcBlockchainManager.transactionSortMode(blockchainType: adapter.blockchainType) return adapter.sendSingle( - amount: amountInputService.amount, - address: address.raw, - feeRate: feeRate, - pluginData: pluginData, - sortMode: sortMode, - logger: logger + amount: amountInputService.amount, + address: address.raw, + feeRate: feeRate, + pluginData: pluginData, + sortMode: sortMode, + logger: logger ) } - } extension SendBitcoinAdapterService { - private enum UpdatedField: String { case amount, address, pluginData, feeRate } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinFactory.swift index dec43be9ea..587652b702 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinFactory.swift @@ -1,6 +1,6 @@ -import UIKit -import MarketKit import HsToolKit +import MarketKit +import UIKit protocol ISendConfirmationFactory { func confirmationViewController() throws -> UIViewController @@ -11,7 +11,6 @@ protocol ISendFeeSettingsFactory { } class BaseSendFactory { - func values(fiatService: FiatService) throws -> (CoinValue, CurrencyValue?) { guard let token = fiatService.token else { throw ConfirmationError.noCoin @@ -21,27 +20,27 @@ class BaseSendFactory { var currencyValue: CurrencyValue? switch fiatService.primaryInfo { - case .amount(let value): + case let .amount(value): coinValue = CoinValue(kind: .token(token: token), value: value) - case .amountInfo(let info): - guard let info = info else { + case let .amountInfo(info): + guard let info else { throw ConfirmationError.noAmount } switch info { - case .coinValue(let value): coinValue = value - case .currencyValue(let value): currencyValue = value + case let .coinValue(value): coinValue = value + case let .currencyValue(value): currencyValue = value } } if let info = fiatService.secondaryAmountInfo { switch info { - case .coinValue(let value): coinValue = value - case .currencyValue(let value): currencyValue = value + case let .coinValue(value): coinValue = value + case let .currencyValue(value): currencyValue = value } } - guard let coinValue = coinValue else { + guard let coinValue else { throw ConfirmationError.noAmount } @@ -49,17 +48,14 @@ class BaseSendFactory { return (negativeCoinValue, currencyValue) } - } extension BaseSendFactory { - enum ConfirmationError: Error { case noCoin case noAmount case noAddress } - } class SendBitcoinFactory: BaseSendFactory { @@ -106,11 +102,9 @@ class SendBitcoinFactory: BaseSendFactory { return viewItems } - } extension SendBitcoinFactory: ISendConfirmationFactory { - func confirmationViewController() throws -> UIViewController { let items = try items() @@ -121,11 +115,9 @@ extension SendBitcoinFactory: ISendConfirmationFactory { return viewController } - } extension SendBitcoinFactory: ISendFeeSettingsFactory { - func feeSettingsViewController() throws -> UIViewController { var dataSources: [ISendSettingsDataSource] = [] @@ -140,7 +132,7 @@ extension SendBitcoinFactory: ISendFeeSettingsFactory { let inputOutputOrderViewModel = InputOutputOrderViewModel(service: adapterService.inputOutputOrderService) dataSources.append(InputOutputOrderDataSource(viewModel: inputOutputOrderViewModel)) - if let timeLockService = timeLockService { + if let timeLockService { let timeLockViewModel = TimeLockViewModel(service: timeLockService) dataSources.append(TimeLockDataSource(viewModel: timeLockViewModel)) } @@ -149,5 +141,4 @@ extension SendBitcoinFactory: ISendFeeSettingsFactory { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinService.swift index 06bfc2d4a6..c39bef6be4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinService.swift @@ -1,8 +1,8 @@ import Foundation +import HsToolKit import MarketKit -import RxSwift import RxRelay -import HsToolKit +import RxSwift class SendBitcoinService { private let disposeBag = DisposeBag() @@ -36,10 +36,10 @@ class SendBitcoinService { self.mode = mode switch mode { - case .prefilled(let address, let amount): + case let .prefilled(address, amount): addressService.set(text: address) if let amount { addressService.publishAmountRelay.accept(amount) } - case .predefined(let address): addressService.set(text: address) + case let .predefined(address): addressService.set(text: address) case .send: () } @@ -54,7 +54,7 @@ class SendBitcoinService { subscribe(scheduler, disposeBag, addressService.stateObservable) { [weak self] _ in self?.syncState() } subscribe(scheduler, disposeBag, feeRateService.statusObservable) { [weak self] _ in self?.syncState() } - if let timeLockErrorService = timeLockErrorService { + if let timeLockErrorService { subscribe(scheduler, disposeBag, timeLockErrorService.errorObservable) { [weak self] _ in self?.syncState() } @@ -63,8 +63,8 @@ class SendBitcoinService { private func syncState() { guard amountCautionService.amountCaution == nil, - !amountService.amount.isZero else { - + !amountService.amount.isZero + else { state = .notReady return } @@ -91,13 +91,10 @@ class SendBitcoinService { state = .ready } - } extension SendBitcoinService: ISendBaseService { - var stateObservable: Observable { stateRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinViewController.swift index 8cd247ede3..2e4b291bb5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Bitcoin/SendBitcoinViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit import ComponentKit -import SectionsTableView -import RxSwift import RxCocoa +import RxSwift +import SectionsTableView +import ThemeKit +import UIKit class SendBitcoinViewController: BaseSendViewController { private let disposeBag = DisposeBag() @@ -21,25 +21,25 @@ class SendBitcoinViewController: BaseSendViewController { amountCautionViewModel: SendAmountCautionViewModel, recipientViewModel: RecipientAddressViewModel, feeViewModel: SendFeeViewModel, - feeCautionViewModel: ITitledCautionViewModel - ) { - + feeCautionViewModel: ITitledCautionViewModel) + { self.feeCautionViewModel = feeCautionViewModel feeCell = FeeCell(viewModel: feeViewModel, title: "fee_settings.fee".localized) super.init( - confirmationFactory: confirmationFactory, - feeSettingsFactory: feeSettingsFactory, - viewModel: viewModel, - availableBalanceViewModel: availableBalanceViewModel, - amountInputViewModel: amountInputViewModel, - amountCautionViewModel: amountCautionViewModel, - recipientViewModel: recipientViewModel + confirmationFactory: confirmationFactory, + feeSettingsFactory: feeSettingsFactory, + viewModel: viewModel, + availableBalanceViewModel: availableBalanceViewModel, + amountInputViewModel: amountInputViewModel, + amountCautionViewModel: amountCautionViewModel, + recipientViewModel: recipientViewModel ) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -60,7 +60,7 @@ class SendBitcoinViewController: BaseSendViewController { private func handle(caution: TitledCaution?) { feeCautionCell.isVisible = caution != nil - if let caution = caution { + if let caution { feeCautionCell.bind(caution: caution) } @@ -74,31 +74,31 @@ class SendBitcoinViewController: BaseSendViewController { var feeSection: SectionProtocol { Section( - id: "fee", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCell, - id: "fee", - height: .heightDoubleLineCell - ) - ] + id: "fee", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCell, + id: "fee", + height: .heightDoubleLineCell + ), + ] ) } var feeCautionSection: SectionProtocol { Section( - id: "fee-caution", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCautionCell, - id: "fee-caution", - dynamicHeight: { [weak self] containerWidth in - self?.feeCautionCell.cellHeight(containerWidth: containerWidth) ?? 0 - } - ) - ] + id: "fee-caution", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCautionCell, + id: "fee-caution", + dynamicHeight: { [weak self] containerWidth in + self?.feeCautionCell.cellHeight(containerWidth: containerWidth) ?? 0 + } + ), + ] ) } @@ -107,10 +107,9 @@ class SendBitcoinViewController: BaseSendViewController { sections.append(contentsOf: [ feeSection, feeCautionSection, - buttonSection + buttonSection, ]) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendBaseService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendBaseService.swift index 78d6f987da..8023ca8f2c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendBaseService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendBaseService.swift @@ -3,7 +3,6 @@ import Foundation struct SendBaseService {} extension SendBaseService { - enum State { case loading case ready @@ -17,7 +16,7 @@ extension SendBaseService { var amount: Decimal? { switch self { - case .prefilled(_, let amount): return amount + case let .prefilled(_, amount): return amount default: return nil } } @@ -31,5 +30,4 @@ extension SendBaseService { enum AmountWarning { case coinNeededForFee } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendViewModel.swift index f737cec607..667a6490b4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/SendViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxCocoa import EvmKit import MarketKit +import RxCocoa +import RxSwift protocol ISendBaseService { var token: Token { get } @@ -15,7 +15,7 @@ class SendViewModel { private let disposeBag = DisposeBag() private let proceedEnabledRelay = BehaviorRelay(value: false) - private let proceedRelay = PublishRelay<()>() + private let proceedRelay = PublishRelay() private var firstLoaded: Bool = false @@ -40,16 +40,14 @@ class SendViewModel { proceedEnabledRelay.accept(false) } } - } extension SendViewModel { - var proceedEnableDriver: Driver { proceedEnabledRelay.asDriver() } - var proceedSignal: Signal<()> { + var proceedSignal: Signal { proceedRelay.asSignal() } @@ -78,5 +76,4 @@ extension SendViewModel { proceedRelay.accept(()) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashFactory.swift index 160eef541e..e07d770df1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashFactory.swift @@ -1,6 +1,6 @@ -import UIKit -import MarketKit import HsToolKit +import MarketKit +import UIKit class SendZcashFactory: BaseSendFactory { private let service: SendZcashService @@ -41,11 +41,9 @@ class SendZcashFactory: BaseSendFactory { return viewItems } - } extension SendZcashFactory: ISendConfirmationFactory { - func confirmationViewController() throws -> UIViewController { let items = try items() @@ -56,5 +54,4 @@ extension SendZcashFactory: ISendConfirmationFactory { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashService.swift index bd87213215..56bc325902 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashService.swift @@ -1,8 +1,8 @@ import Foundation +import HsToolKit import MarketKit -import RxSwift import RxRelay -import HsToolKit +import RxSwift import ZcashLightClientKit class SendZcashService { @@ -42,10 +42,10 @@ class SendZcashService { self.mode = mode switch mode { - case .prefilled(let address, let amount): + case let .prefilled(address, amount): addressService.set(text: address) if let amount { addressService.publishAmountRelay.accept(amount) } - case .predefined(let address): addressService.set(text: address) + case let .predefined(address): addressService.set(text: address) case .send: () } @@ -66,8 +66,8 @@ class SendZcashService { isMemoAvailable = addressType.map { $0 == .shielded } ?? false guard amountCautionService.amountCaution == nil, - !amountService.amount.isZero else { - + !amountService.amount.isZero + else { state = .notReady return } @@ -84,24 +84,20 @@ class SendZcashService { state = .ready } - } extension SendZcashService: ISendBaseService { - var stateObservable: Observable { stateRelay.asObservable() } - } extension SendZcashService: ISendService { - - func sendSingle(logger: HsToolKit.Logger) -> RxSwift.Single { + func sendSingle(logger _: HsToolKit.Logger) -> RxSwift.Single { let address: Address switch addressService.state { - case .success(let sendAddress): address = sendAddress - case .fetchError(let error): return Single.error(error) + case let .success(sendAddress): address = sendAddress + case let .fetchError(error): return Single.error(error) default: return Single.error(AppError.addressInvalid) } @@ -114,16 +110,14 @@ extension SendZcashService: ISendService { } return adapter.sendSingle( - amount: amountService.amount, - address: recipient, - memo: memoService.memo.flatMap({ try? Memo(string: $0) }) + amount: amountService.amount, + address: recipient, + memo: memoService.memo.flatMap { try? Memo(string: $0) } ) } - } extension SendZcashService: ISendXFeeValueService { - var feeState: DataStatus { .completed(adapter.fee) } @@ -131,11 +125,9 @@ extension SendZcashService: ISendXFeeValueService { var feeStateObservable: Observable> { .just(feeState) } - } extension SendZcashService: IAvailableBalanceService { - var availableBalance: DataStatus { .completed(adapter.availableBalance) } @@ -143,11 +135,9 @@ extension SendZcashService: IAvailableBalanceService { var availableBalanceObservable: Observable> { .just(availableBalance) } - } extension SendZcashService: IMemoAvailableService { - var isAvailable: Bool { isMemoAvailable } @@ -155,5 +145,4 @@ extension SendZcashService: IMemoAvailableService { var isAvailableObservable: Observable { isMemoAvailableRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashViewController.swift index 4eec9d28ca..7292ee97fe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Platforms/Zcash/SendZcashViewController.swift @@ -1,10 +1,9 @@ -import UIKit -import ThemeKit -import SnapKit import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class SendZcashViewController: BaseSendViewController { - private let memoCell: SendMemoInputCell private let feeCell: FeeCell @@ -15,22 +14,23 @@ class SendZcashViewController: BaseSendViewController { amountCautionViewModel: SendAmountCautionViewModel, recipientViewModel: RecipientAddressViewModel, memoViewModel: SendMemoInputViewModel, - feeViewModel: SendFeeViewModel - ) { + feeViewModel: SendFeeViewModel) + { memoCell = SendMemoInputCell(viewModel: memoViewModel, topInset: .margin12) feeCell = FeeCell(viewModel: feeViewModel, title: "fee_settings.fee".localized) super.init( - confirmationFactory: confirmationFactory, - viewModel: viewModel, - availableBalanceViewModel: availableBalanceViewModel, - amountInputViewModel: amountInputViewModel, - amountCautionViewModel: amountCautionViewModel, - recipientViewModel: recipientViewModel + confirmationFactory: confirmationFactory, + viewModel: viewModel, + availableBalanceViewModel: availableBalanceViewModel, + amountInputViewModel: amountInputViewModel, + amountCautionViewModel: amountCautionViewModel, + recipientViewModel: recipientViewModel ) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -55,30 +55,30 @@ class SendZcashViewController: BaseSendViewController { var memoSection: SectionProtocol { Section( - id: "memo", - rows: [ - StaticRow( - cell: memoCell, - id: "memo-input", - dynamicHeight: { [weak self] width in - self?.memoCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "memo", + rows: [ + StaticRow( + cell: memoCell, + id: "memo-input", + dynamicHeight: { [weak self] width in + self?.memoCell.height(containerWidth: width) ?? 0 + } + ), + ] ) } var feeSection: SectionProtocol { Section( - id: "fee", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCell, - id: "fee", - height: .heightCell48 - ) - ] + id: "fee", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCell, + id: "fee", + height: .heightCell48 + ), + ] ) } @@ -87,10 +87,9 @@ class SendZcashViewController: BaseSendViewController { sections.append(contentsOf: [ memoSection, feeSection, - buttonSection + buttonSection, ]) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateDataSource.swift index 4025b1ca69..5966ead73a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateDataSource.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class FeeRateDataSource { private let feeRateViewModel: FeeRateViewModel @@ -14,10 +14,10 @@ class FeeRateDataSource { private let feeRateCell: StepperAmountInputCell weak var tableView: SectionsTableView? - var onOpenInfo: ((String, String) -> ())? = nil - var present: ((UIViewController) -> ())? = nil - var onUpdateAlteredState: (() -> ())? = nil - var onCaution: ((TitledCaution?) -> ())? = nil + var onOpenInfo: ((String, String) -> Void)? + var present: ((UIViewController) -> Void)? + var onUpdateAlteredState: (() -> Void)? + var onCaution: ((TitledCaution?) -> Void)? init(feeViewModel: SendFeeViewModel, feeRateViewModel: FeeRateViewModel) { self.feeRateViewModel = feeRateViewModel @@ -44,58 +44,55 @@ class FeeRateDataSource { feeRateCell.set(cautionType: caution?.type) onCaution?(caution) } - } extension FeeRateDataSource: ISendSettingsDataSource { - var altered: Bool { feeRateViewModel.altered } var buildSections: [SectionProtocol] { - guard let tableView = tableView else { + guard let tableView else { return [] } return [ Section( - id: "fee", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: feeCell, - id: "fee-cell", - height: .heightDoubleLineCell - ) - ] + id: "fee", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: feeCell, + id: "fee-cell", + height: .heightDoubleLineCell + ), + ] ), Section( - id: "fee-rate", - headerState: .margin(height: .margin24), - rows: [ - tableView.subtitleWithInfoButtonRow(text: "fee_settings.fee_rate".localized + " (Sat/Byte)", uppercase: false) { [weak self] in - self?.present?(InfoModule.feeInfo) - }, - StaticRow( - cell: feeRateCell, - id: "fee-rate-cell", - height: .heightCell48 - ), - tableView.descriptionRow( - id: "fee-rate-description-cell", - text: "fee_settings.fee_rate.description".localized, - font: .subhead2, - textColor: .themeGray, - ignoreBottomMargin: true - ) - ] - ) + id: "fee-rate", + headerState: .margin(height: .margin24), + rows: [ + tableView.subtitleWithInfoButtonRow(text: "fee_settings.fee_rate".localized + " (Sat/Byte)", uppercase: false) { [weak self] in + self?.present?(InfoModule.feeInfo) + }, + StaticRow( + cell: feeRateCell, + id: "fee-rate-cell", + height: .heightCell48 + ), + tableView.descriptionRow( + id: "fee-rate-description-cell", + text: "fee_settings.fee_rate.description".localized, + font: .subhead2, + textColor: .themeGray, + ignoreBottomMargin: true + ), + ] + ), ] } func onTapReset() { feeRateViewModel.reset() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateService.swift index 0d6fd662f2..2e7e510f9e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import HsExtensions +import RxCocoa +import RxRelay +import RxSwift class FeeRateService { private var tasks = Set() @@ -32,11 +32,9 @@ class FeeRateService { setRecommendedFeeRate() } - } extension FeeRateService { - var statusObservable: Observable> { statusRelay.asObservable() } @@ -70,5 +68,4 @@ extension FeeRateService { } }.store(in: &tasks) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateViewModel.swift index 677ed0d069..f55ee849c9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/FeeRate/FeeRateViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import Foundation +import RxCocoa +import RxRelay +import RxSwift class FeeRateViewModel { private let disposeBag = DisposeBag() @@ -29,7 +29,7 @@ class FeeRateViewModel { } private func syncCaution() { - var caution: TitledCaution? = nil + var caution: TitledCaution? if let amountCaution = amountCautionViewModel.amountCaution { caution = amountCaution @@ -41,21 +41,19 @@ class FeeRateViewModel { } private func sync(feeRateStatus: DataStatus) { - if case .completed(let feeRate) = feeRateStatus { + if case let .completed(feeRate) = feeRateStatus { feeRateRelay.accept(Decimal(feeRate)) } else { feeRateRelay.accept(nil) } } - private func sync(usingRecommended: Bool) { - alteredStateRelay.accept(Void()) + private func sync(usingRecommended _: Bool) { + alteredStateRelay.accept(()) } - } extension FeeRateViewModel { - var altered: Bool { !service.usingRecommended } @@ -79,5 +77,4 @@ extension FeeRateViewModel { var cautionDriver: Driver { cautionRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderDataSource.swift index 166534ff4d..c8cbd92c9b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderDataSource.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class InputOutputOrderDataSource { private let viewModel: InputOutputOrderViewModel @@ -13,10 +13,10 @@ class InputOutputOrderDataSource { private let orderCell: DropDownListCell weak var tableView: SectionsTableView? - var onOpenInfo: ((String, String) -> ())? = nil - var present: ((UIViewController) -> ())? = nil - var onUpdateAlteredState: (() -> ())? = nil - var onCaution: ((TitledCaution?) -> ())? = nil + var onOpenInfo: ((String, String) -> Void)? + var present: ((UIViewController) -> Void)? + var onUpdateAlteredState: (() -> Void)? + var onCaution: ((TitledCaution?) -> Void)? init(viewModel: InputOutputOrderViewModel) { self.viewModel = viewModel @@ -33,57 +33,54 @@ class InputOutputOrderDataSource { private func showList() { let viewController = SelectorModule.bottomSingleSelectorViewController( - image: .local(name: "arrow_medium_2_up_right_24", tint: .gray), - title: "fee_settings.transaction_settings".localized, - viewItems: viewModel.itemsList, - onSelect: { [weak self] index in - self?.viewModel.onSelect(index) - } + image: .local(name: "arrow_medium_2_up_right_24", tint: .gray), + title: "fee_settings.transaction_settings".localized, + viewItems: viewModel.itemsList, + onSelect: { [weak self] index in + self?.viewModel.onSelect(index) + } ) present?(viewController) } - } extension InputOutputOrderDataSource: ISendSettingsDataSource { - var altered: Bool { viewModel.altered } var buildSections: [SectionProtocol] { - guard let tableView = tableView else { + guard let tableView else { return [] } return [ Section( - id: "input-order", - headerState: .margin(height: .margin24), - rows: [ - tableView.subtitleWithInfoButtonRow(text: "fee_settings.transaction_settings".localized, uppercase: false) { [weak self] in - self?.present?(InfoModule.transactionInputsOutputsInfo) - }, - StaticRow( - cell: orderCell, - id: "input-order-cell", - height: .heightDoubleLineCell - ), - tableView.descriptionRow( - id: "input-order-description-cell", - text: "fee_settings.transaction_settings.description".localized, - font: .subhead2, - textColor: .themeGray, - ignoreBottomMargin: true - ) - ] - ) + id: "input-order", + headerState: .margin(height: .margin24), + rows: [ + tableView.subtitleWithInfoButtonRow(text: "fee_settings.transaction_settings".localized, uppercase: false) { [weak self] in + self?.present?(InfoModule.transactionInputsOutputsInfo) + }, + StaticRow( + cell: orderCell, + id: "input-order-cell", + height: .heightDoubleLineCell + ), + tableView.descriptionRow( + id: "input-order-description-cell", + text: "fee_settings.transaction_settings.description".localized, + font: .subhead2, + textColor: .themeGray, + ignoreBottomMargin: true + ), + ] + ), ] } func onTapReset() { viewModel.reset() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderService.swift index 44bee5c95f..8727b0b2fa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderService.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift class InputOutputOrderService { private let blockchainType: BlockchainType @@ -12,7 +12,7 @@ class InputOutputOrderService { private let selectedItemRelay = BehaviorSubject(value: .bip69) private(set) var selectedItem: TransactionDataSortMode = .bip69 { didSet { - if (oldValue != selectedItem) { + if oldValue != selectedItem { selectedItemRelay.onNext(selectedItem) } } @@ -26,11 +26,9 @@ class InputOutputOrderService { setSelectedItemFromSettings() } - } extension InputOutputOrderService { - var selectedItemObservable: Observable { selectedItemRelay.asObservable() } @@ -47,5 +45,4 @@ extension InputOutputOrderService { func setSelectedItemFromSettings() { selectedItem = initialItem } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderViewModel.swift index fd03cd4903..cbd5d23c15 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/InputOutputOrder/InputOutputOrderViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import Foundation +import RxCocoa +import RxRelay +import RxSwift class InputOutputOrderViewModel { private let disposeBag = DisposeBag() @@ -20,11 +20,9 @@ class InputOutputOrderViewModel { private func sync(selectedItem: TransactionDataSortMode) { selectedItemRelay.accept(selectedItem.title) } - } extension InputOutputOrderViewModel { - var altered: Bool { service.selectedItem != service.initialItem } @@ -55,13 +53,10 @@ extension InputOutputOrderViewModel { service.setSelectedItemFromSettings() alteredStateRelay.accept(()) } - } extension InputOutputOrderViewModel: IDropDownListViewModel { - var selectedItemDriver: Driver { selectedItemRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/SendSettingsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/SendSettingsViewController.swift index a3c4dcf176..141d9ecfbc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/SendSettingsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/SendSettingsViewController.swift @@ -1,17 +1,17 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit protocol ISendSettingsDataSource: AnyObject { var tableView: SectionsTableView? { get set } - var onOpenInfo: ((String, String) -> ())? { get set } - var present: ((UIViewController) -> ())? { get set } - var onUpdateAlteredState: (() -> ())? { get set } - var onCaution: ((TitledCaution?) -> ())? { get set } + var onOpenInfo: ((String, String) -> Void)? { get set } + var present: ((UIViewController) -> Void)? { get set } + var onUpdateAlteredState: (() -> Void)? { get set } + var onCaution: ((TitledCaution?) -> Void)? { get set } var altered: Bool { get } var buildSections: [SectionProtocol] { get } @@ -66,7 +66,8 @@ class SendSettingsViewController: ThemeViewController { navigationItem.leftBarButtonItem?.isEnabled = false } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -114,7 +115,7 @@ class SendSettingsViewController: ThemeViewController { private func handle(caution: TitledCaution?) { cautionCell.isVisible = caution != nil - if let caution = caution { + if let caution { cautionCell.bind(caution: caution) } @@ -125,31 +126,28 @@ class SendSettingsViewController: ThemeViewController { } } } - } extension SendSettingsViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { - let dataSourceSections = dataSources.map{ $0.buildSections }.reduce([], +) + let dataSourceSections = dataSources.map(\.buildSections).reduce([], +) let cautionsSections: [SectionProtocol] = [ Section( - id: "caution", - headerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: cautionCell, - id: "caution", - dynamicHeight: { [weak self] containerWidth in - self?.cautionCell.cellHeight(containerWidth: containerWidth) ?? 0 - } - ) - ] - ) + id: "caution", + headerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: cautionCell, + id: "caution", + dynamicHeight: { [weak self] containerWidth in + self?.cautionCell.cellHeight(containerWidth: containerWidth) ?? 0 + } + ), + ] + ), ] return dataSourceSections + cautionsSections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/SendTimeLockErrorService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/SendTimeLockErrorService.swift index d2ca9c12cc..0a5773a7c5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/SendTimeLockErrorService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/SendTimeLockErrorService.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class SendTimeLockErrorService { private let disposeBag = DisposeBag() @@ -10,7 +10,7 @@ class SendTimeLockErrorService { private let adapter: ISendBitcoinAdapter private let errorRelay = BehaviorRelay(value: nil) - private(set) var error: Error? = nil { + private(set) var error: Error? { didSet { errorRelay.accept(error) } @@ -31,7 +31,8 @@ class SendTimeLockErrorService { private func sync() { guard !timeLockService.pluginData.isEmpty, - let address = addressService.state.address else { + let address = addressService.state.address + else { error = nil return } @@ -43,13 +44,10 @@ class SendTimeLockErrorService { self.error = error.convertedError } } - } extension SendTimeLockErrorService: IErrorService { - var errorObservable: Observable { errorRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockDataSource.swift index 3ecbc3538b..ef8f4d1e82 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockDataSource.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class TimeLockDataSource { private let viewModel: TimeLockViewModel @@ -13,10 +13,10 @@ class TimeLockDataSource { private let lockTimeCell: DropDownListCell weak var tableView: SectionsTableView? - var onOpenInfo: ((String, String) -> ())? = nil - var present: ((UIViewController) -> ())? = nil - var onUpdateAlteredState: (() -> ())? = nil - var onCaution: ((TitledCaution?) -> ())? = nil + var onOpenInfo: ((String, String) -> Void)? + var present: ((UIViewController) -> Void)? + var onUpdateAlteredState: (() -> Void)? + var onCaution: ((TitledCaution?) -> Void)? init(viewModel: TimeLockViewModel) { self.viewModel = viewModel @@ -33,52 +33,49 @@ class TimeLockDataSource { private func showList() { let alertController: UIViewController = AlertRouter.module( - title: "fee_settings.time_lock".localized, - viewItems: viewModel.itemsList + title: "fee_settings.time_lock".localized, + viewItems: viewModel.itemsList ) { [weak self] index in self?.viewModel.onSelect(index) } present?(alertController) } - } extension TimeLockDataSource: ISendSettingsDataSource { - var altered: Bool { viewModel.altered } var buildSections: [SectionProtocol] { - guard let tableView = tableView else { + guard let tableView else { return [] } return [ Section( - id: "time-lock", - headerState: .margin(height: .margin24), - rows: [ - StaticRow( - cell: lockTimeCell, - id: "time-lock-cell", - height: .heightDoubleLineCell - ), - tableView.descriptionRow( - id: "time-lock-description-cell", - text: "fee_settings.time_lock.description".localized, - font: .subhead2, - textColor: .themeGray, - ignoreBottomMargin: true - ) - ] - ) + id: "time-lock", + headerState: .margin(height: .margin24), + rows: [ + StaticRow( + cell: lockTimeCell, + id: "time-lock-cell", + height: .heightDoubleLineCell + ), + tableView.descriptionRow( + id: "time-lock-description-cell", + text: "fee_settings.time_lock.description".localized, + font: .subhead2, + textColor: .themeGray, + ignoreBottomMargin: true + ), + ] + ), ] } func onTapReset() { viewModel.reset() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockService.swift index 61a0c13299..444ed0ac3e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockService.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxRelay -import RxCocoa import Hodler +import RxCocoa +import RxRelay +import RxSwift class TimeLockService { private var disposeBag = DisposeBag() @@ -32,11 +32,9 @@ class TimeLockService { } var lockTimeList = Item.allCases - } extension TimeLockService { - var lockTimeObservable: Observable { lockTimeRelay.asObservable() } @@ -52,11 +50,9 @@ extension TimeLockService { lockTime = lockTimeList[index] } - } extension TimeLockService { - enum Item: UInt16, CaseIterable { case none case hour @@ -77,7 +73,5 @@ extension TimeLockService { var title: String { HodlerPlugin.LockTimeInterval.title(lockTimeInterval: lockTimeInterval) } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockViewModel.swift index ccc5ff0f03..f37950bd64 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/Settings/TimeLock/TimeLockViewModel.swift @@ -1,8 +1,8 @@ -import RxSwift -import RxRelay -import RxCocoa import Foundation import Hodler +import RxCocoa +import RxRelay +import RxSwift class TimeLockViewModel { private let disposeBag = DisposeBag() @@ -21,11 +21,9 @@ class TimeLockViewModel { private func sync(lockTime: TimeLockService.Item) { valueRelay.accept(lockTime.title) } - } extension TimeLockViewModel { - var altered: Bool { service.lockTime != .none } @@ -49,21 +47,17 @@ extension TimeLockViewModel { service.set(index: 0) alteredStateRelay.accept(()) } - } extension TimeLockViewModel: IDropDownListViewModel { - var selectedItemDriver: Driver { valueRelay.asDriver() } - } extension HodlerPlugin.LockTimeInterval { - static func title(lockTimeInterval: HodlerPlugin.LockTimeInterval?) -> String { - guard let lockTimeInterval = lockTimeInterval else { + guard let lockTimeInterval else { return "send.hodler_locktime_off".localized } @@ -74,5 +68,4 @@ extension HodlerPlugin.LockTimeInterval { case .year: return "send.hodler_locktime_year".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Send/SwiftUI/SendAmountViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Send/SwiftUI/SendAmountViewModel.swift index 6620e0bd63..6126cb4a99 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Send/SwiftUI/SendAmountViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Send/SwiftUI/SendAmountViewModel.swift @@ -7,10 +7,9 @@ class SendAmountViewModel: ObservableObject { @Published var inputType: InputType = .coin @Published var text: String = "" { - didSet { - - } + didSet {} } + @Published var coinAmount: Decimal = 0 @Published var currencyAmount: Decimal = 0 diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/AmountInputViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/AmountInputViewModel.swift index b6c9602e2f..7349e8cdad 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/AmountInputViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/AmountInputViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift protocol IAmountInputService { var amount: Decimal { get } @@ -17,11 +17,9 @@ protocol IAmountInputService { } extension IAmountInputService { - var amountWarningObservable: Observable { Observable.just(nil) } - } open class AmountInputViewModel { @@ -89,7 +87,7 @@ open class AmountInputViewModel { private func sync(amountWarning: AmountWarning?) { amountWarningRelay.accept(amountWarning.flatMap { warning in switch warning { - case .highPriceImpact(let priceImpact): return "-\(priceImpact.description)%" + case let .highPriceImpact(priceImpact): return "-\(priceImpact.description)%" } }) } @@ -100,7 +98,7 @@ open class AmountInputViewModel { } } - private func sync(balance: Decimal?) { + private func sync(balance _: Decimal?) { queue.async { [weak self] in self?.updateMaxEnabled() } @@ -137,13 +135,13 @@ open class AmountInputViewModel { private func prefix(primaryInfo: FiatService.PrimaryInfo) -> String? { switch primaryInfo { - case .amountInfo(let amountInfo): - guard let amountInfo = amountInfo else { + case let .amountInfo(amountInfo): + guard let amountInfo else { return nil } switch amountInfo { - case .currencyValue(let currencyValue): return currencyValue.currency.symbol + case let .currencyValue(currencyValue): return currencyValue.currency.symbol default: return nil } default: @@ -155,10 +153,10 @@ open class AmountInputViewModel { private func amountString(primaryInfo: FiatService.PrimaryInfo) -> String? { switch primaryInfo { - case .amountInfo(let amountInfo): + case let .amountInfo(amountInfo): amountTypeRelay.accept(InputType.inputType(amountInfo: amountInfo)) - guard let amountInfo = amountInfo else { + guard let amountInfo else { return nil } @@ -168,7 +166,7 @@ open class AmountInputViewModel { decimalFormatter.maximumSignificantDigits = amountInfo.value.significandDigits(fractionDigits: amountInfo.decimal) return decimalFormatter.string(from: amountInfo.value as NSDecimalNumber) - case .amount(let amount): + case let .amount(amount): amountTypeRelay.accept(.coin) if amount == 0 { @@ -182,7 +180,7 @@ open class AmountInputViewModel { private func sync(primaryInfo: FiatService.PrimaryInfo) { switch primaryInfo { - case .amountInfo(let amountInfo): + case let .amountInfo(amountInfo): amountTypeRelay.accept(InputType.inputType(amountInfo: amountInfo)) prefixTypeRelay.accept(InputType.inputType(amountInfo: amountInfo)) case .amount: @@ -198,11 +196,9 @@ open class AmountInputViewModel { secondaryTextTypeRelay.accept(InputType.inputType(amountInfo: amountInfo)) secondaryTextRelay.accept(amountInfo?.formattedFull) } - } extension AmountInputViewModel { - var amount: Decimal { service.amount } @@ -287,11 +283,9 @@ extension AmountInputViewModel { func onSwitch() { switchService.toggle() } - } extension AmountInputViewModel { - enum InputType { case coin case currency @@ -307,7 +301,6 @@ extension AmountInputViewModel { enum AmountWarning { case highPriceImpact(priceImpact: Decimal) } - } extension AmountInputViewModel: IAmountPublishService {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Cells/SendAvailableBalanceCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Cells/SendAvailableBalanceCell.swift index 02eea8e960..2f07f3dbdf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Cells/SendAvailableBalanceCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Cells/SendAvailableBalanceCell.swift @@ -1,7 +1,7 @@ -import UIKit -import SnapKit import HUD import RxSwift +import SnapKit +import UIKit class SendAvailableBalanceCell: UITableViewCell { let cellHeight: CGFloat = 40 @@ -60,7 +60,8 @@ class SendAvailableBalanceCell: UITableViewCell { subscribe(disposeBag, viewModel.viewStateDriver) { [weak self] in self?.sync(viewState: $0) } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -73,12 +74,11 @@ class SendAvailableBalanceCell: UITableViewCell { spinner.stopAnimating() } - if case .loaded(let value) = viewState { + if case let .loaded(value) = viewState { availableAmountValueLabel.text = value availableAmountValueLabel.isHidden = false } else { availableAmountValueLabel.isHidden = true } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationModule.swift index 587439ee39..7a7f277f8c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationModule.swift @@ -1,9 +1,9 @@ -import Foundation -import UIKit -import ThemeKit import EvmKit -import MarketKit +import Foundation import HsExtensions +import MarketKit +import ThemeKit +import UIKit struct SendEvmData { let transactionData: TransactionData @@ -25,19 +25,19 @@ struct SendEvmData { case oneInchSwap(info: OneInchSwapInfo) var dAppInfo: DAppInfo? { - if case .otherDApp(let info) = self { return info } else { return nil } + if case let .otherDApp(info) = self { return info } else { return nil } } var sendInfo: SendInfo? { - if case .send(let info) = self { return info } else { return nil } + if case let .send(info) = self { return info } else { return nil } } var swapInfo: SwapInfo? { - if case .uniswap(let info) = self { return info } else { return nil } + if case let .uniswap(info) = self { return info } else { return nil } } var oneInchSwapInfo: OneInchSwapInfo? { - if case .oneInchSwap(let info) = self { return info } else { return nil } + if case let .oneInchSwap(info) = self { return info } else { return nil } } } @@ -75,26 +75,25 @@ struct SendEvmData { let slippage: Decimal let recipient: Address? } - } -struct SendEvmConfirmationModule { +enum SendEvmConfirmationModule { private static let forceMultiplier: Double = 1.2 static func viewController(evmKitWrapper: EvmKitWrapper, sendData: SendEvmData) -> UIViewController? { let evmKit = evmKitWrapper.evmKit guard let coinServiceFactory = EvmCoinServiceFactory( - blockchainType: evmKitWrapper.blockchainType, - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - coinManager: App.shared.coinManager + blockchainType: evmKitWrapper.blockchainType, + marketKit: App.shared.marketKit, + currencyManager: App.shared.currencyManager, + coinManager: App.shared.coinManager ) else { return nil } guard let (settingsService, settingsViewModel) = EvmSendSettingsModule.instance( - evmKit: evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory + evmKit: evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory ) else { return nil } @@ -124,10 +123,10 @@ struct SendEvmConfirmationModule { let evmKitWrapper = adapter.evmKitWrapper guard let coinServiceFactory = EvmCoinServiceFactory( - blockchainType: evmKitWrapper.blockchainType, - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - coinManager: App.shared.coinManager + blockchainType: evmKitWrapper.blockchainType, + marketKit: App.shared.marketKit, + currencyManager: App.shared.currencyManager, + coinManager: App.shared.coinManager ) else { throw CreateModuleError.cantCreateFeeRateProvider } @@ -146,8 +145,8 @@ struct SendEvmConfirmationModule { } guard let (settingsService, settingsViewModel) = EvmSendSettingsModule.instance( - evmKit: evmKitWrapper.evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory, - previousTransaction: transaction, predefinedGasLimit: gasLimit + evmKit: evmKitWrapper.evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory, + previousTransaction: transaction, predefinedGasLimit: gasLimit ) else { throw CreateModuleError.cantCreateFeeSettingsModule } @@ -164,11 +163,9 @@ struct SendEvmConfirmationModule { return SendEvmConfirmationViewController(mode: mode, transactionViewModel: viewModel, settingsViewModel: settingsViewModel) } - } extension SendEvmConfirmationModule { - enum CreateModuleError: LocalizedError { case wrongTransaction case cantCreateFeeRateProvider @@ -181,9 +178,7 @@ extension SendEvmConfirmationModule { case .alreadyInBlock: return "tx_info.transaction.already_in_block".localized } } - } - } enum ResendEvmTransactionType { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationViewController.swift index b0be25db0b..997ac94c89 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/Confirmation/SendEvmConfirmationViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import SnapKit -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class SendEvmConfirmationViewController: SendEvmTransactionViewController { private let mode: Mode @@ -17,7 +17,8 @@ class SendEvmConfirmationViewController: SendEvmTransactionViewController { super.init(transactionViewModel: transactionViewModel, settingsViewModel: settingsViewModel) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -82,15 +83,12 @@ class SendEvmConfirmationViewController: SendEvmTransactionViewController { sendSliderButton.reset() } - } extension SendEvmConfirmationViewController { - enum Mode { case send case resend case cancel } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendAvailableBalanceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendAvailableBalanceViewModel.swift index c75c952ae0..1497d284ec 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendAvailableBalanceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendAvailableBalanceViewModel.swift @@ -1,7 +1,7 @@ +import BigInt import Foundation -import RxSwift import RxCocoa -import BigInt +import RxSwift protocol IAvailableBalanceService: AnyObject { var availableBalance: DataStatus { get } @@ -52,7 +52,7 @@ class SendAvailableBalanceViewModel { weakSelf.viewStateRelay.accept(.loading) } case .failed: weakSelf.updateViewState(availableBalance: 0) - case .completed(let availableBalance): weakSelf.updateViewState(availableBalance: availableBalance) + case let .completed(availableBalance): weakSelf.updateViewState(availableBalance: availableBalance) } } } @@ -70,22 +70,17 @@ class SendAvailableBalanceViewModel { viewStateRelay.accept(.loaded(value: value)) } - } extension SendAvailableBalanceViewModel: ISendAvailableBalanceViewModel { - var viewStateDriver: Driver { viewStateRelay.asDriver() } - } extension SendAvailableBalanceViewModel { - enum ViewState { case loading case loaded(value: String?) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmModule.swift index 22bde41bb7..b57f2f42e0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmModule.swift @@ -1,28 +1,28 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit class SendEvmModule { - static func viewController(token: Token, mode: SendBaseService.Mode, adapter: ISendEthereumAdapter) -> UIViewController { let evmAddressParserItem = EvmAddressParser() let udnAddressParserItem = UdnAddressParserItem.item(rawAddressParserItem: evmAddressParserItem, coinCode: token.coin.code, token: token) let addressParserChain = AddressParserChain() - .append(handler: evmAddressParserItem) - .append(handler: udnAddressParserItem) + .append(handler: evmAddressParserItem) + .append(handler: udnAddressParserItem) if let httpSyncSource = App.shared.evmSyncSourceManager.httpSyncSource(blockchainType: .ethereum), - let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) { + let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) + { addressParserChain.append(handler: ensAddressParserItem) } let addressUriParser = AddressParserFactory.parser(blockchainType: token.blockchainType, tokenType: token.type) let addressService = AddressService( - mode: .parsers(addressUriParser, addressParserChain), - marketKit: App.shared.marketKit, - contactBookManager: App.shared.contactManager, - blockchainType: token.blockchainType + mode: .parsers(addressUriParser, addressParserChain), + marketKit: App.shared.marketKit, + contactBookManager: App.shared.contactManager, + blockchainType: token.blockchainType ) let service = SendEvmService(token: token, mode: mode, adapter: adapter, addressService: addressService) @@ -38,24 +38,23 @@ class SendEvmModule { let availableBalanceViewModel = SendAvailableBalanceViewModel(service: service, coinService: coinService, switchService: switchService) let amountViewModel = AmountInputViewModel( - service: service, - fiatService: fiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: service, + fiatService: fiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) addressService.amountPublishService = amountViewModel let recipientViewModel = RecipientAddressViewModel(service: addressService, handlerDelegate: nil) let viewController = SendEvmViewController( - evmKitWrapper: adapter.evmKitWrapper, - viewModel: viewModel, - availableBalanceViewModel: availableBalanceViewModel, - amountViewModel: amountViewModel, - recipientViewModel: recipientViewModel + evmKitWrapper: adapter.evmKitWrapper, + viewModel: viewModel, + availableBalanceViewModel: availableBalanceViewModel, + amountViewModel: amountViewModel, + recipientViewModel: recipientViewModel ) return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmService.swift index 0e56af2448..659d66db67 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmService.swift @@ -38,10 +38,10 @@ class SendEvmService { self.addressService = addressService switch mode { - case .prefilled(let address, let amount): + case let .prefilled(address, amount): addressService.set(text: address) if let amount { addressService.publishAmountRelay.accept(amount) } - case .predefined(let address): addressService.set(text: address) + case let .predefined(address): addressService.set(text: address) case .send: () } @@ -63,7 +63,7 @@ class SendEvmService { } private func syncState() { - if amountCaution.error == nil, case .success = addressService.state, let evmAmount = evmAmount, let addressData = addressData { + if amountCaution.error == nil, case .success = addressService.state, let evmAmount, let addressData { let transactionData = adapter.transactionData(amount: evmAmount, address: addressData.evmAddress) let sendInfo = SendEvmData.SendInfo(domain: addressData.domain) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewController.swift index 5a2e59f6ca..fd8333976d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import EvmKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class SendEvmViewController: ThemeViewController { private let evmKitWrapper: EvmKitWrapper @@ -41,7 +41,8 @@ class SendEvmViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -134,84 +135,81 @@ class SendEvmViewController: ThemeViewController { } navigationController?.pushViewController(viewController, animated: true) } - } extension SendEvmViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [ Section( - id: "available-balance", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: availableBalanceCell, - id: "available-balance", - height: availableBalanceCell.cellHeight - ) - ] + id: "available-balance", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: availableBalanceCell, + id: "available-balance", + height: availableBalanceCell.cellHeight + ), + ] ), Section( - id: "amount", + id: "amount", + headerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: amountCell, + id: "amount-input", + height: amountCell.cellHeight + ), + StaticRow( + cell: amountCautionCell, + id: "amount-caution", + dynamicHeight: { [weak self] width in + self?.amountCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), + ] + + if viewModel.showAddress { + sections.append( + Section( + id: "recipient", headerState: .margin(height: .margin16), rows: [ StaticRow( - cell: amountCell, - id: "amount-input", - height: amountCell.cellHeight + cell: recipientCell, + id: "recipient-input", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } ), StaticRow( - cell: amountCautionCell, - id: "amount-caution", - dynamicHeight: { [weak self] width in - self?.amountCautionCell.height(containerWidth: width) ?? 0 - } - ) + cell: recipientCautionCell, + id: "recipient-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), ] - ) - ] - - if viewModel.showAddress { - sections.append( - Section( - id: "recipient", - headerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: recipientCell, - id: "recipient-input", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "recipient-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + ) ) } sections.append( - Section( + Section( + id: "button", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: buttonCell, id: "button", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: buttonCell, - id: "button", - height: PrimaryButtonCell.height - ) - ] - ) + height: PrimaryButtonCell.height + ), + ] + ) ) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewModel.swift index d1ce340702..266c67a4c5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvm/SendEvmViewModel.swift @@ -1,8 +1,8 @@ -import Foundation -import RxSwift -import RxCocoa import EvmKit +import Foundation import MarketKit +import RxCocoa +import RxSwift class SendEvmViewModel { private let service: SendEvmService @@ -30,7 +30,7 @@ class SendEvmViewModel { } private func sync(amountCaution: (error: Error?, warning: SendEvmService.AmountWarning?)) { - var caution: Caution? = nil + var caution: Caution? if let error = amountCaution.error { caution = Caution(text: error.smartDescription, type: .error) @@ -42,11 +42,9 @@ class SendEvmViewModel { amountCautionRelay.accept(caution) } - } extension SendEvmViewModel { - var title: String { switch service.mode { case .send, .prefilled: return "send.title".localized(token.coin.code) @@ -78,22 +76,19 @@ extension SendEvmViewModel { } func didTapProceed() { - guard case .ready(let sendData) = service.state else { + guard case let .ready(sendData) = service.state else { return } proceedRelay.accept(sendData) } - } extension SendEvmService.AmountError: LocalizedError { - var errorDescription: String? { switch self { case .insufficientBalance: return "send.amount_error.balance".localized default: return "\(self)" } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmCautionsFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmCautionsFactory.swift index d5e9387737..37d736f28b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmCautionsFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmCautionsFactory.swift @@ -1,5 +1,4 @@ class SendEvmCautionsFactory { - func items(errors: [Error], warnings: [Warning], baseCoinService: CoinService) -> [TitledCaution] { var warningCautions = [TitledCaution]() @@ -9,10 +8,10 @@ class SendEvmCautionsFactory { case .insufficientBalance: return [ TitledCaution( - title: "fee_settings.errors.insufficient_balance".localized, - text: "fee_settings.errors.insufficient_balance.info".localized(baseCoinService.token.coin.code), - type: .error - ) + title: "fee_settings.errors.insufficient_balance".localized, + text: "fee_settings.errors.insufficient_balance.info".localized(baseCoinService.token.coin.code), + type: .error + ), ] } } else if let error = error as? NonceService.NonceError { @@ -20,21 +19,20 @@ class SendEvmCautionsFactory { case .alreadyInUse: return [ TitledCaution( - title: "evm_send_settings.nonce.errors.already_in_use".localized, - text: "evm_send_settings.nonce.errors.already_in_use.info".localized(baseCoinService.token.coin.code), - type: .error - ) + title: "evm_send_settings.nonce.errors.already_in_use".localized, + text: "evm_send_settings.nonce.errors.already_in_use.info".localized(baseCoinService.token.coin.code), + type: .error + ), ] } } else if let error = error as? UniswapModule.UniswapError { switch error { - case .forbiddenPriceImpact(let provider): + case let .forbiddenPriceImpact(provider): return [ - TitledCaution(title: "swap.price_impact".localized, text: "swap.confirmation.impact_too_high".localized(AppConfig.appName, provider), type: .error) + TitledCaution(title: "swap.price_impact".localized, text: "swap.confirmation.impact_too_high".localized(AppConfig.appName, provider), type: .error), ] } - } - else { + } else { return [convert(error: error, baseCoinService: baseCoinService)] } } @@ -64,18 +62,18 @@ class SendEvmCautionsFactory { var title: String? = nil var text: String? = nil - if case SendEvmTransactionService.TransactionError.insufficientBalance(let requiredBalance) = error { + if case let SendEvmTransactionService.TransactionError.insufficientBalance(requiredBalance) = error { let amountData = baseCoinService.amountData(value: requiredBalance) title = "fee_settings.errors.insufficient_balance".localized text = "ethereum_transaction.error.insufficient_balance".localized(amountData.formattedFull) } - if case AppError.ethereum(let reason) = error.convertedError { + if case let AppError.ethereum(reason) = error.convertedError { switch reason { case .insufficientBalanceWithFee: title = "fee_settings.errors.insufficient_balance".localized text = "ethereum_transaction.error.insufficient_balance_with_fee".localized(baseCoinService.token.coin.code) - case .executionReverted(let message): + case let .executionReverted(message): title = "fee_settings.errors.unexpected_error".localized text = message case .lowerThanBaseGasLimit: @@ -96,7 +94,7 @@ class SendEvmCautionsFactory { } } - if case AppError.oneInch(let reason) = error.convertedError { + if case let AppError.oneInch(reason) = error.convertedError { switch reason { case .insufficientBalanceWithFee: title = "fee_settings.errors.insufficient_balance".localized @@ -111,10 +109,9 @@ class SendEvmCautionsFactory { } return TitledCaution( - title: title ?? "ethereum_transaction.error.title".localized, - text: text ?? error.convertedError.smartDescription, - type: .error + title: title ?? "ethereum_transaction.error.title".localized, + text: text ?? error.convertedError.smartDescription, + type: .error ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionService.swift index f31530a40c..0bad0d0582 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionService.swift @@ -1,11 +1,11 @@ -import Foundation -import RxSwift -import RxCocoa -import EvmKit import BigInt +import EvmKit +import Foundation import MarketKit -import UniswapKit import OneInchKit +import RxCocoa +import RxSwift +import UniswapKit protocol ISendEvmTransactionService { var state: SendEvmTransactionService.State { get } @@ -53,10 +53,10 @@ class SendEvmTransactionService { self.evmLabelManager = evmLabelManager dataState = DataState( - transactionData: sendData.transactionData, - additionalInfo: sendData.additionalInfo, - decoration: evmKitWrapper.evmKit.decorate(transactionData: sendData.transactionData), - nonce: settingsService.nonceService.frozen ? settingsService.nonceService.nonce : nil + transactionData: sendData.transactionData, + additionalInfo: sendData.additionalInfo, + decoration: evmKitWrapper.evmKit.decorate(transactionData: sendData.transactionData), + nonce: settingsService.nonceService.frozen ? settingsService.nonceService.nonce : nil ) subscribe(disposeBag, settingsService.statusObservable) { [weak self] in self?.sync(status: $0) } @@ -74,10 +74,10 @@ class SendEvmTransactionService { switch status { case .loading: state = .notReady(errors: [], warnings: []) - case .failed(let error): + case let .failed(error): syncDataState() state = .notReady(errors: [error], warnings: []) - case .completed(let fallibleTransaction): + case let .completed(fallibleTransaction): syncDataState(transaction: fallibleTransaction.data) let warnings = sendData.warnings + fallibleTransaction.warnings @@ -94,17 +94,15 @@ class SendEvmTransactionService { let transactionData = transaction?.transactionData ?? sendData.transactionData dataState = DataState( - transactionData: transactionData, - additionalInfo: sendData.additionalInfo, - decoration: evmKit.decorate(transactionData: transactionData), - nonce: settingsService.nonceService.frozen ? settingsService.nonceService.nonce : nil + transactionData: transactionData, + additionalInfo: sendData.additionalInfo, + decoration: evmKit.decorate(transactionData: transactionData), + nonce: settingsService.nonceService.frozen ? settingsService.nonceService.nonce : nil ) } - } extension SendEvmTransactionService: ISendEvmTransactionService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -126,7 +124,7 @@ extension SendEvmTransactionService: ISendEvmTransactionService { } func send() { - guard case .ready = state, case .completed(let fallibleTransaction) = settingsService.status else { + guard case .ready = state, case let .completed(fallibleTransaction) = settingsService.status else { return } let transaction = fallibleTransaction.data @@ -134,24 +132,22 @@ extension SendEvmTransactionService: ISendEvmTransactionService { sendState = .sending evmKitWrapper.sendSingle( - transactionData: transaction.transactionData, - gasPrice: transaction.gasData.price, - gasLimit: transaction.gasData.limit, - nonce: transaction.nonce - ) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] fullTransaction in - self?.sendState = .sent(transactionHash: fullTransaction.transaction.hash) - }, onError: { error in - self.sendState = .failed(error: error) - }) - .disposed(by: disposeBag) + transactionData: transaction.transactionData, + gasPrice: transaction.gasData.price, + gasLimit: transaction.gasData.limit, + nonce: transaction.nonce + ) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] fullTransaction in + self?.sendState = .sent(transactionHash: fullTransaction.transaction.hash) + }, onError: { error in + self.sendState = .failed(error: error) + }) + .disposed(by: disposeBag) } - } extension SendEvmTransactionService { - enum State { case ready(warnings: [Warning]) case notReady(errors: [Error], warnings: [Warning]) @@ -175,5 +171,4 @@ extension SendEvmTransactionService { case noTransactionData case insufficientBalance(requiredBalance: BigUInt) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewController.swift index f1495a7abb..99ef08bafc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewController.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit import Foundation import MarketKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class SendEvmTransactionViewController: ThemeViewController { let disposeBag = DisposeBag() @@ -36,7 +36,8 @@ class SendEvmTransactionViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -87,11 +88,11 @@ class SendEvmTransactionViewController: ThemeViewController { let value = nonce.flatMap { "\(NSDecimalNumber(decimal: $0).intValue)" } ?? "" CellBuilderNew.buildStatic( - cell: nonceCell, - rootElement: .hStack([ - .textElement(text: .subhead2("send.confirmation.nonce".localized)), - .textElement(text: .subhead1(value), parameters: [.allCompression, .rightAlignment]) - ]) + cell: nonceCell, + rootElement: .hStack([ + .textElement(text: .subhead2("send.confirmation.nonce".localized)), + .textElement(text: .subhead1(value), parameters: [.allCompression, .rightAlignment]), + ]) ) } @@ -113,10 +114,9 @@ class SendEvmTransactionViewController: ThemeViewController { reloadTable() } - func handleSending() { - } + func handleSending() {} - func handleSendSuccess(transactionHash: Data) { + func handleSendSuccess(transactionHash _: Data) { dismiss(animated: true) } @@ -161,7 +161,7 @@ class SendEvmTransactionViewController: ThemeViewController { case let .doubleAmount(title, coinValue, currencyValue): return CellComponent.doubleAmountRow(tableView: tableView, rowInfo: rowInfo, title: title, coinValue: coinValue, currencyValue: currencyValue) case let .address(title, value, valueTitle, contactAddress): - var onAddToContact: (() -> ())? = nil + var onAddToContact: (() -> Void)? = nil if let contactAddress { onAddToContact = { [weak self] in ContactBookModule.showAddition(contactAddress: contactAddress, parentViewController: self) @@ -170,7 +170,7 @@ class SendEvmTransactionViewController: ThemeViewController { return CellComponent.fromToRow(tableView: tableView, rowInfo: rowInfo, title: title, value: value, valueTitle: valueTitle, onAddToContact: onAddToContact) case let .value(title, value, type): return CellComponent.valueRow(tableView: tableView, rowInfo: rowInfo, iconName: nil, title: title, value: value, type: type) - case .input(let value): + case let .input(value): return CellComponent.fromToRow(tableView: tableView, rowInfo: rowInfo, title: "Input", value: value, valueTitle: nil) } } @@ -178,23 +178,21 @@ class SendEvmTransactionViewController: ThemeViewController { private func section(sectionViewItem: SendEvmTransactionViewModel.SectionViewItem, index: Int) -> SectionProtocol { var headerText: String? - if index == 0, let topDescription = topDescription { + if index == 0, let topDescription { headerText = topDescription } return Section( - id: "section_\(index)", - headerState: headerText.map { tableView.sectionFooter(text: $0) } ?? .margin(height: .margin12), - rows: sectionViewItem.viewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, rowInfo: RowInfo(index: index, isFirst: index == 0, isLast: index == sectionViewItem.viewItems.count - 1)) - } + id: "section_\(index)", + headerState: headerText.map { tableView.sectionFooter(text: $0) } ?? .margin(height: .margin12), + rows: sectionViewItem.viewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, rowInfo: RowInfo(index: index, isFirst: index == 0, isLast: index == sectionViewItem.viewItems.count - 1)) + } ) } - } extension SendEvmTransactionViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { let transactionSections: [SectionProtocol] = sectionViewItems.enumerated().map { index, sectionViewItem in section(sectionViewItem: sectionViewItem, index: index) @@ -202,66 +200,66 @@ extension SendEvmTransactionViewController: SectionsDataSource { var settingsSections: [SectionProtocol] = [] - if settingsViewModel.nonceViewModel.altered && !settingsViewModel.nonceViewModel.frozen { + if settingsViewModel.nonceViewModel.altered, !settingsViewModel.nonceViewModel.frozen { settingsSections.append( - Section( + Section( + id: "nonce", + headerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: nonceCell, id: "nonce", - headerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: nonceCell, - id: "nonce", - height: .heightCell48, - autoDeselect: true - ) - ] - ) + height: .heightCell48, + autoDeselect: true + ), + ] + ) ) } settingsSections.append( - Section( + Section( + id: "fee", + headerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: feeCell, id: "fee", - headerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: feeCell, - id: "fee", - height: .heightDoubleLineCell - ) - ] - ) + height: .heightDoubleLineCell + ), + ] + ) ) let cautionsSections: [SectionProtocol] = [ Section( - id: "caution1", - headerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: caution1Cell, - id: "caution1", - dynamicHeight: { [weak self] containerWidth in - self?.caution1Cell.cellHeight(containerWidth: containerWidth) ?? 0 - } - ) - ] + id: "caution1", + headerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: caution1Cell, + id: "caution1", + dynamicHeight: { [weak self] containerWidth in + self?.caution1Cell.cellHeight(containerWidth: containerWidth) ?? 0 + } + ), + ] ), Section( - id: "caution2", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: caution2Cell, - id: "caution2", - dynamicHeight: { [weak self] containerWidth in - self?.caution2Cell.cellHeight(containerWidth: containerWidth) ?? 0 - } - )] - ) + id: "caution2", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: caution2Cell, + id: "caution2", + dynamicHeight: { [weak self] containerWidth in + self?.caution2Cell.cellHeight(containerWidth: containerWidth) ?? 0 + } + ), + ] + ), ] return transactionSections + settingsSections + cautionsSections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewModel.swift index 55d4c828a0..0bc2cd6b29 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendEvmTransaction/SendEvmTransactionViewModel.swift @@ -1,14 +1,14 @@ -import Foundation -import RxSwift -import RxCocoa -import EvmKit import BigInt -import UniswapKit -import OneInchKit import Eip20Kit -import NftKit -import MarketKit +import EvmKit +import Foundation import HsExtensions +import MarketKit +import NftKit +import OneInchKit +import RxCocoa +import RxSwift +import UniswapKit class SendEvmTransactionViewModel { private let disposeBag = DisposeBag() @@ -24,7 +24,7 @@ class SendEvmTransactionViewModel { private let sendEnabledRelay = BehaviorRelay(value: false) private let cautionsRelay = BehaviorRelay<[TitledCaution]>(value: []) - private let sendingRelay = PublishRelay<()>() + private let sendingRelay = PublishRelay() private let sendSuccessRelay = PublishRelay() private let sendFailedRelay = PublishRelay() @@ -52,10 +52,10 @@ class SendEvmTransactionViewModel { private func sync(state: SendEvmTransactionService.State) { switch state { - case .ready(let warnings): + case let .ready(warnings): cautionsRelay.accept(cautionsFactory.items(errors: [], warnings: warnings, baseCoinService: coinServiceFactory.baseCoinService)) sendEnabledRelay.accept(true) - case .notReady(let errors, let warnings): + case let .notReady(errors, warnings): cautionsRelay.accept(cautionsFactory.items(errors: errors, warnings: warnings, baseCoinService: coinServiceFactory.baseCoinService)) sendEnabledRelay.accept(false) } @@ -99,19 +99,19 @@ class SendEvmTransactionViewModel { switch sendState { case .idle: () case .sending: sendingRelay.accept(()) - case .sent(let transactionHash): sendSuccessRelay.accept(transactionHash) - case .failed(let error): sendFailedRelay.accept(error.convertedError.smartDescription) + case let .sent(transactionHash): sendSuccessRelay.accept(transactionHash) + case let .failed(error): sendFailedRelay.accept(error.convertedError.smartDescription) } } private func items(dataState: SendEvmTransactionService.DataState) -> [SectionViewItem] { - if let decoration = dataState.decoration, let items = self.items(decoration: decoration, transactionData: dataState.transactionData, additionalInfo: dataState.additionalInfo, nonce: dataState.nonce) { + if let decoration = dataState.decoration, let items = items(decoration: decoration, transactionData: dataState.transactionData, additionalInfo: dataState.additionalInfo, nonce: dataState.nonce) { return items } if let additionalInfo = dataState.additionalInfo { switch additionalInfo { - case .oneInchSwap(let info): + case let .oneInchSwap(info): return oneInchItems(oneInchSwapInfo: info) default: () } @@ -124,83 +124,83 @@ class SendEvmTransactionViewModel { return [] } - private func items(decoration: TransactionDecoration, transactionData: TransactionData?, additionalInfo: SendEvmData.AdditionInfo?, nonce: Int?) -> [SectionViewItem]? { + private func items(decoration: TransactionDecoration, transactionData _: TransactionData?, additionalInfo: SendEvmData.AdditionInfo?, nonce: Int?) -> [SectionViewItem]? { switch decoration { case let decoration as OutgoingDecoration: return sendBaseCoinItems( - to: decoration.to, - value: decoration.value, - sendInfo: additionalInfo?.sendInfo, - nonce: nonce + to: decoration.to, + value: decoration.value, + sendInfo: additionalInfo?.sendInfo, + nonce: nonce ) case let decoration as OutgoingEip20Decoration: return eip20TransferItems( - to: decoration.to, - value: decoration.value, - contractAddress: decoration.contractAddress, - nonce: nonce, - sendInfo: additionalInfo?.sendInfo + to: decoration.to, + value: decoration.value, + contractAddress: decoration.contractAddress, + nonce: nonce, + sendInfo: additionalInfo?.sendInfo ) case let decoration as Eip721SafeTransferFromDecoration: return nftTransferItems( - to: decoration.to, - value: 1, - nonce: nonce, - sendInfo: additionalInfo?.sendInfo, - tokenId: decoration.tokenId + to: decoration.to, + value: 1, + nonce: nonce, + sendInfo: additionalInfo?.sendInfo, + tokenId: decoration.tokenId ) case let decoration as Eip1155SafeTransferFromDecoration: return nftTransferItems( - to: decoration.to, - value: decoration.value, - nonce: nonce, - sendInfo: additionalInfo?.sendInfo, - tokenId: decoration.tokenId + to: decoration.to, + value: decoration.value, + nonce: nonce, + sendInfo: additionalInfo?.sendInfo, + tokenId: decoration.tokenId ) case let decoration as ApproveEip20Decoration: return eip20ApproveItems( - spender: decoration.spender, - value: decoration.value, - contractAddress: decoration.contractAddress, - additionalInfo: additionalInfo, - nonce: nonce + spender: decoration.spender, + value: decoration.value, + contractAddress: decoration.contractAddress, + additionalInfo: additionalInfo, + nonce: nonce ) case let decoration as SwapDecoration: return uniswapItems( - amountIn: decoration.amountIn, - amountOut: decoration.amountOut, - tokenIn: decoration.tokenIn, - tokenOut: decoration.tokenOut, - recipient: decoration.recipient, - deadline: decoration.deadline, - swapInfo: additionalInfo?.swapInfo, - nonce: nonce + amountIn: decoration.amountIn, + amountOut: decoration.amountOut, + tokenIn: decoration.tokenIn, + tokenOut: decoration.tokenOut, + recipient: decoration.recipient, + deadline: decoration.deadline, + swapInfo: additionalInfo?.swapInfo, + nonce: nonce ) case let decoration as OneInchSwapDecoration: return oneInchItems( - tokenIn: decoration.tokenIn, - tokenOut: decoration.tokenOut, - amountIn: decoration.amountIn, - amountOut: decoration.amountOut, - recipient: decoration.recipient, - oneInchSwapInfo: additionalInfo?.oneInchSwapInfo, - nonce: nonce + tokenIn: decoration.tokenIn, + tokenOut: decoration.tokenOut, + amountIn: decoration.amountIn, + amountOut: decoration.amountOut, + recipient: decoration.recipient, + oneInchSwapInfo: additionalInfo?.oneInchSwapInfo, + nonce: nonce ) case let decoration as OneInchUnoswapDecoration: return oneInchItems( - tokenIn: decoration.tokenIn, - tokenOut: decoration.tokenOut, - amountIn: decoration.amountIn, - amountOut: decoration.amountOut, - oneInchSwapInfo: additionalInfo?.oneInchSwapInfo, - nonce: nonce + tokenIn: decoration.tokenIn, + tokenOut: decoration.tokenOut, + amountIn: decoration.amountIn, + amountOut: decoration.amountOut, + oneInchSwapInfo: additionalInfo?.oneInchSwapInfo, + nonce: nonce ) case is OneInchUnknownSwapDecoration: @@ -223,11 +223,11 @@ class SendEvmTransactionViewModel { let token = coinService.token return .amount( - iconUrl: token.coin.imageUrl, - iconPlaceholderImageName: token.placeholderImageName, - coinAmount: ValueFormatter.instance.formatFull(coinValue: amountData.coinValue) ?? "n/a".localized, - currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, - type: type + iconUrl: token.coin.imageUrl, + iconPlaceholderImageName: token.placeholderImageName, + coinAmount: ValueFormatter.instance.formatFull(coinValue: amountData.coinValue) ?? "n/a".localized, + currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, + type: type ) } @@ -237,11 +237,11 @@ class SendEvmTransactionViewModel { let coinAmount = ValueFormatter.instance.formatFull(coinValue: amountData.coinValue) ?? "n/a".localized return .amount( - iconUrl: token.coin.imageUrl, - iconPlaceholderImageName: token.placeholderImageName, - coinAmount: "\(coinAmount) \("swap.estimate_short".localized)", - currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, - type: type + iconUrl: token.coin.imageUrl, + iconPlaceholderImageName: token.placeholderImageName, + coinAmount: "\(coinAmount) \("swap.estimate_short".localized)", + currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) }, + type: type ) } @@ -255,10 +255,10 @@ class SendEvmTransactionViewModel { } return .nftAmount( - iconUrl: iconUrl, - iconPlaceholderImageName: "placeholder_nft_32", - nftAmount: nftAmount, - type: type + iconUrl: iconUrl, + iconPlaceholderImageName: "placeholder_nft_32", + nftAmount: nftAmount, + type: type ) } @@ -266,9 +266,9 @@ class SendEvmTransactionViewModel { let amountData = coinService.amountData(value: value, sign: .plus) return .doubleAmount( - title: title, - coinAmount: ValueFormatter.instance.formatFull(coinValue: amountData.coinValue) ?? "n/a".localized, - currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) } + title: title, + coinAmount: ValueFormatter.instance.formatFull(coinValue: amountData.coinValue) ?? "n/a".localized, + currencyAmount: amountData.currencyValue.flatMap { ValueFormatter.instance.formatFull(currencyValue: $0) } ) } @@ -277,29 +277,29 @@ class SendEvmTransactionViewModel { let contactData = contactLabelService.contactData(for: toValue) var viewItems: [ViewItem] = [ - .subhead( - iconName: "arrow_medium_2_up_right_24", - title: "send.confirmation.you_send".localized, - value: coinServiceFactory.baseCoinService.token.coin.name - ), - amountViewItem( - coinService: coinServiceFactory.baseCoinService, - value: value, - type: .neutral - ), - .address( - title: "send.confirmation.to".localized, - value: toValue, - valueTitle: sendInfo?.domain ?? evmLabelManager.addressLabel(address: toValue), - contactAddress: contactData.contactAddress - ), - ] + .subhead( + iconName: "arrow_medium_2_up_right_24", + title: "send.confirmation.you_send".localized, + value: coinServiceFactory.baseCoinService.token.coin.name + ), + amountViewItem( + coinService: coinServiceFactory.baseCoinService, + value: value, + type: .neutral + ), + .address( + title: "send.confirmation.to".localized, + value: toValue, + valueTitle: sendInfo?.domain ?? evmLabelManager.addressLabel(address: toValue), + contactAddress: contactData.contactAddress + ), + ] if let contactName = contactData.name { viewItems.append(.value(title: "send.confirmation.contact_name".localized, value: contactName, type: .regular)) } - if let nonce = nonce { + if let nonce { viewItems.append(.value(title: "send.confirmation.nonce".localized, value: nonce.description, type: .regular)) } @@ -313,15 +313,15 @@ class SendEvmTransactionViewModel { var viewItems: [ViewItem] = [ .subhead( - iconName: "arrow_medium_2_up_right_24", - title: "send.confirmation.you_send".localized, - value: coinService.token.coin.name + iconName: "arrow_medium_2_up_right_24", + title: "send.confirmation.you_send".localized, + value: coinService.token.coin.name ), amountViewItem( - coinService: coinService, - value: value, - type: .neutral - ) + coinService: coinService, + value: value, + type: .neutral + ), ] let addressValue = to.eip55 @@ -330,16 +330,16 @@ class SendEvmTransactionViewModel { let contactData = contactLabelService.contactData(for: addressValue) viewItems.append(.address( - title: "send.confirmation.to".localized, - value: addressValue, - valueTitle: addressTitle, - contactAddress: contactData.contactAddress - ) + title: "send.confirmation.to".localized, + value: addressValue, + valueTitle: addressTitle, + contactAddress: contactData.contactAddress + ) ) if let contactName = contactData.name { viewItems.append(.value(title: "send.confirmation.contact_name".localized, value: contactName, type: .regular)) } - if let nonce = nonce { + if let nonce { viewItems.append(.value(title: "send.confirmation.nonce".localized, value: nonce.description, type: .regular)) } @@ -347,14 +347,13 @@ class SendEvmTransactionViewModel { } private func nftTransferItems(to: EvmKit.Address, value: BigUInt, nonce: Int?, sendInfo: SendEvmData.SendInfo?, tokenId: BigUInt) -> [SectionViewItem]? { - var viewItems: [ViewItem] = [ .subhead( - iconName: "arrow_medium_2_up_right_24", - title: "send.confirmation.you_send".localized, - value: sendInfo?.assetShortMetadata?.displayName ?? "#\(tokenId.description)" + iconName: "arrow_medium_2_up_right_24", + title: "send.confirmation.you_send".localized, + value: sendInfo?.assetShortMetadata?.displayName ?? "#\(tokenId.description)" ), - nftAmountViewItem(value: value, type: .neutral, iconUrl: sendInfo?.assetShortMetadata?.previewImageUrl) + nftAmountViewItem(value: value, type: .neutral, iconUrl: sendInfo?.assetShortMetadata?.previewImageUrl), ] let addressValue = to.eip55 @@ -363,16 +362,16 @@ class SendEvmTransactionViewModel { let contactData = contactLabelService.contactData(for: addressValue) viewItems.append(.address( - title: "send.confirmation.to".localized, - value: addressValue, - valueTitle: addressTitle, - contactAddress: contactData.contactAddress - ) + title: "send.confirmation.to".localized, + value: addressValue, + valueTitle: addressTitle, + contactAddress: contactData.contactAddress + ) ) if let contactName = contactData.name { viewItems.append(.value(title: "send.confirmation.contact_name".localized, value: contactName, type: .regular)) } - if let nonce = nonce { + if let nonce { viewItems.append(.value(title: "send.confirmation.nonce".localized, value: nonce.description, type: .regular)) } @@ -384,21 +383,21 @@ class SendEvmTransactionViewModel { return nil } - let isRevokeAllowance = value == 0 // Check approved new value or revoked last allowance + let isRevokeAllowance = value == 0 // Check approved new value or revoked last allowance let amountItem: ViewItem if isRevokeAllowance { amountItem = .amount( - iconUrl: coinService.token.coin.imageUrl, - iconPlaceholderImageName: coinService.token.placeholderImageName, - coinAmount: coinService.token.coin.code, - currencyAmount: nil, - type: .neutral + iconUrl: coinService.token.coin.imageUrl, + iconPlaceholderImageName: coinService.token.placeholderImageName, + coinAmount: coinService.token.coin.code, + currencyAmount: nil, + type: .neutral ) } else { amountItem = amountViewItem( - coinService: coinService, - value: value, - type: .neutral + coinService: coinService, + value: value, + type: .neutral ) } let addressValue = spender.eip55 @@ -407,24 +406,24 @@ class SendEvmTransactionViewModel { var viewItems: [ViewItem] = [ .subhead( - iconName: "check_2_24", - title: isRevokeAllowance ? "approve.confirmation.you_revoke".localized : "approve.confirmation.you_approve".localized, - value: coinService.token.coin.name + iconName: "check_2_24", + title: isRevokeAllowance ? "approve.confirmation.you_revoke".localized : "approve.confirmation.you_approve".localized, + value: coinService.token.coin.name ), amountItem, .address( - title: "approve.confirmation.spender".localized, - value: addressValue, - valueTitle: addressTitle, - contactAddress: contactData.contactAddress - ) + title: "approve.confirmation.spender".localized, + value: addressValue, + valueTitle: addressTitle, + contactAddress: contactData.contactAddress + ), ] if let contactName = contactData.name { viewItems.append(.value(title: "send.confirmation.contact_name".localized, value: contactName, type: .regular)) } - if let nonce = nonce { + if let nonce { viewItems.append(.value(title: "send.confirmation.nonce".localized, value: nonce.description, type: .regular)) } @@ -435,7 +434,7 @@ class SendEvmTransactionViewModel { return sections } - private func uniswapItems(amountIn: SwapDecoration.Amount, amountOut: SwapDecoration.Amount, tokenIn: SwapDecoration.Token, tokenOut: SwapDecoration.Token, recipient: EvmKit.Address?, deadline: BigUInt?, swapInfo: SendEvmData.SwapInfo?, nonce: Int?) -> [SectionViewItem]? { + private func uniswapItems(amountIn: SwapDecoration.Amount, amountOut: SwapDecoration.Amount, tokenIn: SwapDecoration.Token, tokenOut: SwapDecoration.Token, recipient: EvmKit.Address?, deadline _: BigUInt?, swapInfo: SendEvmData.SwapInfo?, nonce: Int?) -> [SectionViewItem]? { guard let coinServiceIn = coinService(token: tokenIn), let coinServiceOut = coinService(token: tokenOut) else { return nil } @@ -443,11 +442,11 @@ class SendEvmTransactionViewModel { var sections = [SectionViewItem]() var inViewItems: [ViewItem] = [ - .subhead(iconName: "arrow_medium_2_up_right_24", title: "swap.you_pay".localized, value: coinServiceIn.token.coin.name) + .subhead(iconName: "arrow_medium_2_up_right_24", title: "swap.you_pay".localized, value: coinServiceIn.token.coin.name), ] switch amountIn { - case .exact(let value): + case let .exact(value): inViewItems.append(amountViewItem(coinService: coinServiceIn, value: value, type: .neutral)) case .extremum: if let estimatedIn = swapInfo?.estimatedIn { @@ -458,11 +457,11 @@ class SendEvmTransactionViewModel { sections.append(SectionViewItem(viewItems: inViewItems)) var outViewItems: [ViewItem] = [ - .subhead(iconName: "arrow_medium_2_down_left_24", title: "swap.you_get".localized, value: coinServiceOut.token.coin.name) + .subhead(iconName: "arrow_medium_2_down_left_24", title: "swap.you_get".localized, value: coinServiceOut.token.coin.name), ] switch amountOut { - case .exact(let value): + case let .exact(value): outViewItems.append(amountViewItem(coinService: coinServiceOut, value: value, type: .incoming)) case .extremum: if let estimatedOut = swapInfo?.estimatedOut { @@ -481,17 +480,17 @@ class SendEvmTransactionViewModel { otherViewItems.append(.value(title: "swap.advanced_settings.deadline".localized, value: deadline, type: .regular)) } - if let recipient = recipient { + if let recipient { let addressValue = recipient.eip55 let addressTitle = swapInfo?.recipientDomain ?? evmLabelManager.addressLabel(address: addressValue) let contactData = contactLabelService.contactData(for: addressValue) otherViewItems.append(.address( - title: "swap.advanced_settings.recipient_address".localized, - value: addressValue, - valueTitle: addressTitle, - contactAddress: contactData.contactAddress - ) + title: "swap.advanced_settings.recipient_address".localized, + value: addressValue, + valueTitle: addressTitle, + contactAddress: contactData.contactAddress + ) ) if let contactName = contactData.name { otherViewItems.append(.value(title: "send.confirmation.contact_name".localized, value: contactName, type: .regular)) @@ -512,13 +511,13 @@ class SendEvmTransactionViewModel { otherViewItems.append(.value(title: "swap.price_impact".localized, value: priceImpact.value, type: type)) } - if case .extremum(let value) = amountIn { + if case let .extremum(value) = amountIn { otherViewItems.append(doubleAmountViewItem(coinService: coinServiceIn, title: "swap.confirmation.maximum_sent".localized, value: value)) - } else if case .extremum(let value) = amountOut { + } else if case let .extremum(value) = amountOut { otherViewItems.append(doubleAmountViewItem(coinService: coinServiceOut, title: "swap.confirmation.minimum_received".localized, value: value)) } - if let nonce = nonce { + if let nonce { otherViewItems.append(.value(title: "send.confirmation.nonce".localized, value: nonce.description, type: .regular)) } @@ -532,25 +531,25 @@ class SendEvmTransactionViewModel { private func oneInchItems(tokenIn: OneInchDecoration.Token, tokenOut: OneInchDecoration.Token?, amountIn: BigUInt, amountOut: OneInchDecoration.Amount, recipient: EvmKit.Address? = nil, oneInchSwapInfo: SendEvmData.OneInchSwapInfo?, nonce: Int?) -> [SectionViewItem]? { var coinServiceOut = tokenOut.flatMap { coinService(token: $0) } - if coinServiceOut == nil, let oneInchSwapInfo = oneInchSwapInfo { + if coinServiceOut == nil, let oneInchSwapInfo { coinServiceOut = coinService(token: oneInchSwapInfo.tokenTo) } - guard let coinServiceIn = coinService(token: tokenIn), let coinServiceOut = coinServiceOut else { + guard let coinServiceIn = coinService(token: tokenIn), let coinServiceOut else { return nil } var sections = [SectionViewItem]() sections.append( - SectionViewItem(viewItems: [ - .subhead(iconName: "arrow_medium_2_up_right_24", title: "swap.you_pay".localized, value: coinServiceIn.token.coin.code), - amountViewItem(coinService: coinServiceIn, value: amountIn, type: .neutral) - ]) + SectionViewItem(viewItems: [ + .subhead(iconName: "arrow_medium_2_up_right_24", title: "swap.you_pay".localized, value: coinServiceIn.token.coin.code), + amountViewItem(coinService: coinServiceIn, value: amountIn, type: .neutral), + ]) ) var outViewItems: [ViewItem] = [ - .subhead(iconName: "arrow_medium_2_down_left_24", title: "swap.you_get".localized, value: coinServiceOut.token.coin.code) + .subhead(iconName: "arrow_medium_2_down_left_24", title: "swap.you_get".localized, value: coinServiceOut.token.coin.code), ] switch amountOut { @@ -561,22 +560,23 @@ class SendEvmTransactionViewModel { } } - if let nonce = nonce { + if let nonce { outViewItems.append(.value(title: "send.confirmation.nonce".localized, value: nonce.description, type: .regular)) } sections.append(SectionViewItem(viewItems: outViewItems)) var additionalInfoItems = additionalSectionViewItem(oneInchSwapInfo: oneInchSwapInfo, recipient: recipient) - if let oneInchSwapInfo = oneInchSwapInfo, let item = swapPriceViewItem( - amountFrom: oneInchSwapInfo.amountFrom, - amountTo: oneInchSwapInfo.estimatedAmountTo, - tokenFrom: oneInchSwapInfo.tokenFrom, - tokenTo: oneInchSwapInfo.tokenTo) { + if let oneInchSwapInfo, let item = swapPriceViewItem( + amountFrom: oneInchSwapInfo.amountFrom, + amountTo: oneInchSwapInfo.estimatedAmountTo, + tokenFrom: oneInchSwapInfo.tokenFrom, + tokenTo: oneInchSwapInfo.tokenTo + ) { additionalInfoItems.append(item) } - if case .extremum(let value) = amountOut { + if case let .extremum(value) = amountOut { additionalInfoItems.append(doubleAmountViewItem(coinService: coinServiceOut, title: "swap.confirmation.minimum_received".localized, value: value)) } @@ -593,7 +593,7 @@ class SendEvmTransactionViewModel { sections.append(SectionViewItem(viewItems: [ .subhead(iconName: "arrow_medium_2_up_right_24", title: "swap.you_pay".localized, value: coinServiceIn.token.coin.code), - amountViewItem(coinService: coinServiceIn, value: oneInchSwapInfo.amountFrom, type: .neutral) + amountViewItem(coinService: coinServiceIn, value: oneInchSwapInfo.amountFrom, type: .neutral), ])) let amountOutMinDecimal = oneInchSwapInfo.estimatedAmountTo * (1 - oneInchSwapInfo.slippage / 100) @@ -601,7 +601,7 @@ class SendEvmTransactionViewModel { sections.append(SectionViewItem(viewItems: [ .subhead(iconName: "arrow_medium_2_down_left_24", title: "swap.you_get".localized, value: coinServiceOut.token.coin.code), - estimatedAmountViewItem(coinService: coinServiceOut, value: oneInchSwapInfo.estimatedAmountTo, type: .incoming) + estimatedAmountViewItem(coinService: coinServiceOut, value: oneInchSwapInfo.estimatedAmountTo, type: .incoming), ])) var additionalInfoItems = additionalSectionViewItem(oneInchSwapInfo: oneInchSwapInfo, recipient: oneInchSwapInfo.recipient.flatMap { try? EvmKit.Address(hex: $0.raw) }) @@ -616,7 +616,7 @@ class SendEvmTransactionViewModel { } private func swapPriceViewItem(amountFrom: Decimal, amountTo: Decimal, tokenFrom: MarketKit.Token, tokenTo: MarketKit.Token) -> ViewItem? { - if !amountFrom.isZero && !amountTo.isZero { + if !amountFrom.isZero, !amountTo.isZero { let executionPrice = amountTo / amountFrom let reverted = amountTo < amountFrom @@ -625,7 +625,6 @@ class SendEvmTransactionViewModel { return .value(title: "swap.price".localized, value: fullValue, type: .regular) } return nil - } private func additionalSectionViewItem(oneInchSwapInfo: SendEvmData.OneInchSwapInfo?, recipient: EvmKit.Address?) -> [ViewItem] { @@ -641,11 +640,11 @@ class SendEvmTransactionViewModel { let contactData = contactLabelService.contactData(for: addressValue) viewItems.append(.address( - title: "swap.advanced_settings.recipient_address".localized, - value: addressValue, - valueTitle: addressTitle, - contactAddress: contactData.contactAddress - ) + title: "swap.advanced_settings.recipient_address".localized, + value: addressValue, + valueTitle: addressTitle, + contactAddress: contactData.contactAddress + ) ) if let contactName = contactData.name { viewItems.append(.value(title: "send.confirmation.contact_name".localized, value: contactName, type: .regular)) @@ -661,23 +660,23 @@ class SendEvmTransactionViewModel { var viewItems: [ViewItem] = [ amountViewItem( - coinService: coinServiceFactory.baseCoinService, - value: transactionData.value, - type: .neutral + coinService: coinServiceFactory.baseCoinService, + value: transactionData.value, + type: .neutral ), .address( - title: "send.confirmation.to".localized, - value: toValue, - valueTitle: evmLabelManager.addressLabel(address: toValue), - contactAddress: contactData.contactAddress - ) + title: "send.confirmation.to".localized, + value: toValue, + valueTitle: evmLabelManager.addressLabel(address: toValue), + contactAddress: contactData.contactAddress + ), ] if let contactName = contactData.name { viewItems.append(.value(title: "send.confirmation.contact_name".localized, value: contactName, type: .regular)) } - if let nonce = nonce { + if let nonce { viewItems.append(.value(title: "send.confirmation.nonce".localized, value: nonce.description, type: .regular)) } @@ -698,25 +697,23 @@ class SendEvmTransactionViewModel { private func coinService(token: SwapDecoration.Token) -> CoinService? { switch token { case .evmCoin: return coinServiceFactory.baseCoinService - case .eip20Coin(let address, _): return coinServiceFactory.coinService(contractAddress: address) + case let .eip20Coin(address, _): return coinServiceFactory.coinService(contractAddress: address) } } private func coinService(token: OneInchDecoration.Token) -> CoinService? { switch token { case .evmCoin: return coinServiceFactory.baseCoinService - case .eip20Coin(let address, _): return coinServiceFactory.coinService(contractAddress: address) + case let .eip20Coin(address, _): return coinServiceFactory.coinService(contractAddress: address) } } private func coinService(token: MarketKit.Token) -> CoinService { coinServiceFactory.coinService(token: token) } - } extension SendEvmTransactionViewModel { - var sectionViewItemsDriver: Driver<[SectionViewItem]> { sectionViewItemsRelay.asDriver() } @@ -729,7 +726,7 @@ extension SendEvmTransactionViewModel { cautionsRelay.asDriver() } - var sendingSignal: Signal<()> { + var sendingSignal: Signal { sendingRelay.asSignal() } @@ -744,11 +741,9 @@ extension SendEvmTransactionViewModel { func send() { service.send() } - } extension SendEvmTransactionViewModel { - struct SectionViewItem { let viewItems: [ViewItem] } @@ -762,5 +757,4 @@ extension SendEvmTransactionViewModel { case value(title: String, value: String, type: ValueType) case input(value: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputCell.swift index c964c0d15b..53ff4a7826 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class IntegerAmountInputCell: UITableViewCell { private let formValidatedView: FormValidatedView @@ -21,18 +21,17 @@ class IntegerAmountInputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } override func becomeFirstResponder() -> Bool { formAmountInputView.becomeFirstResponder() } - } extension IntegerAmountInputCell { - var cellHeight: CGFloat { formAmountInputView.viewHeight } @@ -40,5 +39,4 @@ extension IntegerAmountInputCell { func set(cautionType: CautionType?) { formValidatedView.set(cautionType: cautionType) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputView.swift index 2764d978d1..8df2885209 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class IntegerAmountInputView: UIView { let viewHeight: CGFloat = 44 @@ -16,14 +16,15 @@ class IntegerAmountInputView: UIView { syncButtonStates() } } + var clearHidden = false { didSet { syncButtonStates() } } - var onChangeText: ((String?) -> ())? - var onTapMax: (() -> ())? + var onChangeText: ((String?) -> Void)? + var onTapMax: (() -> Void)? init(singleLine: Bool = false) { inputStackView = InputStackView(singleLine: singleLine) @@ -57,7 +58,8 @@ class IntegerAmountInputView: UIView { syncButtonStates() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -79,11 +81,9 @@ class IntegerAmountInputView: UIView { clearView.isHidden = true } } - } extension IntegerAmountInputView { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -121,18 +121,15 @@ extension IntegerAmountInputView { get { inputStackView.editable } set { inputStackView.editable = newValue } } - } extension IntegerAmountInputView: IHeightControlView { // required in FormValidatedView, but not used yet - - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { nil } set {} } - func height(containerWidth: CGFloat) -> CGFloat { + func height(containerWidth _: CGFloat) -> CGFloat { 0 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputViewModel.swift index a59d3cf8e8..f45e07a441 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerAmountInputViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift protocol IIntegerAmountInputService { var amount: Int { get } @@ -24,7 +24,6 @@ class IntegerAmountInputViewModel { private var amountRelay = BehaviorRelay(value: nil) private var isMaxEnabledRelay = BehaviorRelay(value: false) - var amountDisposeBag = DisposeBag() var publishAmountRelay: BehaviorRelay? { didSet { @@ -60,7 +59,7 @@ class IntegerAmountInputViewModel { } } - private func sync(balance: Int?) { + private func sync(balance _: Int?) { queue.async { [weak self] in self?.updateMaxEnabled() } @@ -80,21 +79,20 @@ class IntegerAmountInputViewModel { private func updateMaxEnabled() { isMaxEnabledRelay.accept(isMaxSupported && (service.balance ?? 0) > 0) } - } extension IntegerAmountInputViewModel { - func isValid(amount: String?) -> Bool { guard let string = amount, - let _ = Int(string) else { + let _ = Int(string) + else { return false } return true } func equalValue(lhs: String?, rhs: String?) -> Bool { - lhs.map({ Int($0) }) == rhs.map({ Int($0) }) + lhs.map { Int($0) } == rhs.map { Int($0) } } var amountDriver: Driver { @@ -119,7 +117,6 @@ extension IntegerAmountInputViewModel { amountRelay.accept("\(balance)") service.onChange(amount: balance) } - } extension IntegerAmountInputViewModel: IAmountPublishService {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerFormAmountInputView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerFormAmountInputView.swift index 31cba27b34..72d06beaee 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerFormAmountInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/IntegerAmountInput/IntegerFormAmountInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import RxSwift +import SnapKit +import ThemeKit +import UIKit class IntegerFormAmountInputView: UIView { private let viewModel: IntegerAmountInputViewModel @@ -29,7 +29,8 @@ class IntegerFormAmountInputView: UIView { subscribe(disposeBag, viewModel.isMaxEnabledDriver) { [weak self] in self?.amountInputView.maxButtonVisible = $0 } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -38,17 +39,15 @@ class IntegerFormAmountInputView: UIView { } private func set(amount: String?) { - guard amountInputView.inputText != amount && !viewModel.equalValue(lhs: amountInputView.inputText, rhs: amount) else { //avoid issue with point ("1" and "1.") + guard amountInputView.inputText != amount, !viewModel.equalValue(lhs: amountInputView.inputText, rhs: amount) else { // avoid issue with point ("1" and "1.") return } amountInputView.inputText = amount } - } extension IntegerFormAmountInputView { - var viewHeight: CGFloat { amountInputView.viewHeight } @@ -62,12 +61,10 @@ extension IntegerFormAmountInputView { get { amountInputView.clearHidden } set { amountInputView.clearHidden = newValue } } - } extension IntegerFormAmountInputView: IHeightControlView { - - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { amountInputView.onChangeHeight } set { amountInputView.onChangeHeight = newValue } } @@ -75,5 +72,4 @@ extension IntegerFormAmountInputView: IHeightControlView { func height(containerWidth: CGFloat) -> CGFloat { amountInputView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155AvailableBalanceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155AvailableBalanceViewModel.swift index efbb5b58ca..e3c4db5dfd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155AvailableBalanceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155AvailableBalanceViewModel.swift @@ -1,7 +1,7 @@ +import BigInt import Foundation -import RxSwift import RxCocoa -import BigInt +import RxSwift class SendEip1155AvailableBalanceViewModel { private var queue = DispatchQueue(label: "\(AppConfig.label).available-balance-view-model", qos: .userInitiated) @@ -38,7 +38,7 @@ class SendEip1155AvailableBalanceViewModel { weakSelf.viewStateRelay.accept(.loading) } case .failed: weakSelf.updateViewState(availableBalance: 0) - case .completed(let availableBalance): weakSelf.updateViewState(availableBalance: availableBalance) + case let .completed(availableBalance): weakSelf.updateViewState(availableBalance: availableBalance) } } } @@ -50,13 +50,10 @@ class SendEip1155AvailableBalanceViewModel { viewStateRelay.accept(.loaded(value: value)) } - } extension SendEip1155AvailableBalanceViewModel: ISendAvailableBalanceViewModel { - var viewStateDriver: Driver { viewStateRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155Service.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155Service.swift index 136318a596..a1cd9fce51 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155Service.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155Service.swift @@ -1,11 +1,11 @@ +import BigInt +import EvmKit import Foundation -import UIKit +import Kingfisher import MarketKit -import RxSwift import RxRelay -import EvmKit -import BigInt -import Kingfisher +import RxSwift +import UIKit class SendEip1155Service { let nftUid: NftUid @@ -27,7 +27,7 @@ class SendEip1155Service { private var addressData: AddressData? private let amountCautionRelay = PublishRelay() - private var amountCaution: Error? = nil { + private var amountCaution: Error? { didSet { amountCautionRelay.accept(amountCaution) } @@ -35,7 +35,7 @@ class SendEip1155Service { init(nftUid: NftUid, balance: Int, adapter: INftAdapter, addressService: AddressService, nftMetadataManager: NftMetadataManager) { self.nftUid = nftUid - self.nftBalance = balance + nftBalance = balance self.adapter = adapter self.addressService = addressService @@ -47,9 +47,9 @@ class SendEip1155Service { private func sync(addressState: AddressService.State) { switch addressState { - case .success(let address): + case let .success(address): do { - addressData = AddressData(evmAddress: try EvmKit.Address(hex: address.raw), domain: address.domain) + addressData = try AddressData(evmAddress: EvmKit.Address(hex: address.raw), domain: address.domain) } catch { addressData = nil } @@ -60,7 +60,7 @@ class SendEip1155Service { } private func syncState() { - if case .success = addressService.state, let nftAmount = nftAmount, let addressData = addressData { + if case .success = addressService.state, let nftAmount, let addressData { guard let transactionData = adapter.transferEip1155TransactionData(contractAddress: nftUid.contractAddress, to: addressData.evmAddress, tokenId: nftUid.tokenId, value: Decimal(nftAmount)) else { state = .notReady return @@ -95,11 +95,9 @@ class SendEip1155Service { return nil } } - } extension SendEip1155Service { - var availableBalance: DataStatus { .completed(nftBalance) } @@ -107,11 +105,9 @@ extension SendEip1155Service { var availableBalanceObservable: Observable> { Observable.just(availableBalance) } - } extension SendEip1155Service { - var stateObservable: Observable { stateRelay.asObservable() } @@ -119,13 +115,11 @@ extension SendEip1155Service { var amountCautionObservable: Observable { amountCautionRelay.asObservable() } - } extension SendEip1155Service: IIntegerAmountInputService { - var amount: Int { - if nftBalance == 1 { // if balance == 1 just put it in amount cell + if nftBalance == 1 { // if balance == 1 just put it in amount cell return nftBalance } @@ -160,11 +154,9 @@ extension SendEip1155Service: IIntegerAmountInputService { syncState() } - } extension SendEip1155Service { - enum State { case ready(sendData: SendEvmData) case notReady @@ -178,5 +170,4 @@ extension SendEip1155Service { let evmAddress: EvmKit.Address let domain: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewController.swift index 88e89cefcf..742772b0d3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewController.swift @@ -1,13 +1,13 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa +import ComponentKit import EvmKit import Kingfisher +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit import UIExtensions -import ComponentKit +import UIKit class SendEip1155ViewController: KeyboardAwareViewController { private let evmKitWrapper: EvmKitWrapper @@ -45,7 +45,8 @@ class SendEip1155ViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -102,8 +103,8 @@ class SendEip1155ViewController: KeyboardAwareViewController { override open func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - if !keyboardShown && viewModel.showKeyboard { - DispatchQueue.main.async { + if !keyboardShown, viewModel.showKeyboard { + DispatchQueue.main.async { _ = self.amountCell.becomeFirstResponder() } @@ -136,27 +137,25 @@ class SendEip1155ViewController: KeyboardAwareViewController { } navigationController?.pushViewController(viewController, animated: true) } - } extension SendEip1155ViewController: SectionsDataSource { - private func imageSection(nftImage: NftImage) -> SectionProtocol { Section( - id: "image", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin12), - rows: [ - Row( - id: "image", - dynamicHeight: { width in - NftAssetImageCell.height(containerWidth: width, maxHeight: 120, ratio: nftImage.ratio) - }, - bind: { cell, _ in - cell.bind(nftImage: nftImage, cornerRadius: .cornerRadius8) - } - ) - ] + id: "image", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin12), + rows: [ + Row( + id: "image", + dynamicHeight: { width in + NftAssetImageCell.height(containerWidth: width, maxHeight: 120, ratio: nftImage.ratio) + }, + bind: { cell, _ in + cell.bind(nftImage: nftImage, cornerRadius: .cornerRadius8) + } + ), + ] ) } @@ -171,93 +170,92 @@ extension SendEip1155ViewController: SectionsDataSource { let name = viewModel.name sections.append( - Section( - id: "title", - rows: [ - CellBuilderNew.row( - rootElement: .text { component in - component.font = nameFont - component.textColor = .themeLeah - component.text = name - component.numberOfLines = 0 - component.textAlignment = .center - }, - tableView: tableView, - id: "name", - dynamicHeight: { width in - CellBuilderNew.height( - containerWidth: width, - backgroundStyle: .transparent, - text: name, - font: nameFont, - verticalPadding: .margin12, - elements: [.multiline] - ) - }, - bind: { cell in - cell.set(backgroundStyle: .transparent, isFirst: true) - } + Section( + id: "title", + rows: [ + CellBuilderNew.row( + rootElement: .text { component in + component.font = nameFont + component.textColor = .themeLeah + component.text = name + component.numberOfLines = 0 + component.textAlignment = .center + }, + tableView: tableView, + id: "name", + dynamicHeight: { width in + CellBuilderNew.height( + containerWidth: width, + backgroundStyle: .transparent, + text: name, + font: nameFont, + verticalPadding: .margin12, + elements: [.multiline] ) - ] - ) + }, + bind: { cell in + cell.set(backgroundStyle: .transparent, isFirst: true) + } + ), + ] + ) ) sections.append(contentsOf: [ Section( - id: "available-balance", - headerState: .margin(height: .margin4), - rows: [ - StaticRow( - cell: availableBalanceCell, - id: "available-balance", - height: availableBalanceCell.cellHeight - ) - ] + id: "available-balance", + headerState: .margin(height: .margin4), + rows: [ + StaticRow( + cell: availableBalanceCell, + id: "available-balance", + height: availableBalanceCell.cellHeight + ), + ] ), Section( - id: "amount", - headerState: .margin(height: .margin8), - rows: [ - StaticRow( - cell: amountCell, - id: "amount-input", - height: amountCell.cellHeight - ), - StaticRow( - cell: amountCautionCell, - id: "amount-caution", - dynamicHeight: { [weak self] width in - self?.amountCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + id: "amount", + headerState: .margin(height: .margin8), + rows: [ + StaticRow( + cell: amountCell, + id: "amount-input", + height: amountCell.cellHeight + ), + StaticRow( + cell: amountCautionCell, + id: "amount-caution", + dynamicHeight: { [weak self] width in + self?.amountCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), ]) sections.append( - Section( - id: "recipient", - headerState: .margin(height: .margin12), - rows: [ - StaticRow( - cell: recipientCell, - id: "recipient-input", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "recipient-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + Section( + id: "recipient", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: recipientCell, + id: "recipient-input", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: recipientCautionCell, + id: "recipient-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ) ) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewModel.swift index 1101597a86..96a1a006ca 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip1155/SendEip1155ViewModel.swift @@ -1,8 +1,8 @@ -import Foundation -import RxSwift -import RxCocoa import EvmKit +import Foundation import MarketKit +import RxCocoa +import RxSwift class SendEip1155ViewModel { private let service: SendEip1155Service @@ -30,7 +30,7 @@ class SendEip1155ViewModel { } private func sync(amountCaution: Error?) { - var caution: Caution? = nil + var caution: Caution? if let error = amountCaution { caution = Caution(text: error.smartDescription, type: .error) @@ -38,11 +38,9 @@ class SendEip1155ViewModel { amountCautionRelay.accept(caution) } - } extension SendEip1155ViewModel { - var showKeyboard: Bool { (service.balance ?? 0) != 1 // If balance == 1 don't show keyboard } @@ -68,21 +66,18 @@ extension SendEip1155ViewModel { } func didTapProceed() { - guard case .ready(let sendData) = service.state else { + guard case let .ready(sendData) = service.state else { return } proceedRelay.accept(sendData) } - } extension SendEip1155Service.AmountError: LocalizedError { - var errorDescription: String? { switch self { case .insufficientBalance: return "send.amount_error.balance".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721Service.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721Service.swift index 4db53a55be..98e25aa70d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721Service.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721Service.swift @@ -1,11 +1,11 @@ +import BigInt +import EvmKit import Foundation -import UIKit +import Kingfisher import MarketKit -import RxSwift import RxRelay -import EvmKit -import BigInt -import Kingfisher +import RxSwift +import UIKit class SendEip721Service { let nftUid: NftUid @@ -37,9 +37,9 @@ class SendEip721Service { private func sync(addressState: AddressService.State) { switch addressState { - case .success(let address): + case let .success(address): do { - addressData = AddressData(evmAddress: try EvmKit.Address(hex: address.raw), domain: address.domain) + addressData = try AddressData(evmAddress: EvmKit.Address(hex: address.raw), domain: address.domain) } catch { addressData = nil } @@ -50,7 +50,7 @@ class SendEip721Service { } private func syncState() { - if case .success = addressService.state, let addressData = addressData { + if case .success = addressService.state, let addressData { guard let transactionData = adapter.transferEip721TransactionData(contractAddress: nftUid.contractAddress, to: addressData.evmAddress, tokenId: nftUid.tokenId) else { state = .notReady return @@ -77,19 +77,15 @@ class SendEip721Service { return nil } } - } extension SendEip721Service { - var stateObservable: Observable { stateRelay.asObservable() } - } extension SendEip721Service { - enum State { case ready(sendData: SendEvmData) case notReady @@ -99,5 +95,4 @@ extension SendEip721Service { let evmAddress: EvmKit.Address let domain: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewController.swift index a7407e2cd1..ffd535b3e7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewController.swift @@ -1,13 +1,13 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa +import ComponentKit import EvmKit import Kingfisher +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit import UIExtensions -import ComponentKit +import UIKit class SendEip721ViewController: KeyboardAwareViewController { private let evmKitWrapper: EvmKitWrapper @@ -35,7 +35,8 @@ class SendEip721ViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -108,27 +109,25 @@ class SendEip721ViewController: KeyboardAwareViewController { } navigationController?.pushViewController(viewController, animated: true) } - } extension SendEip721ViewController: SectionsDataSource { - private func imageSection(nftImage: NftImage) -> SectionProtocol { Section( - id: "image", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin12), - rows: [ - Row( - id: "image", - dynamicHeight: { width in - NftAssetImageCell.height(containerWidth: width, maxHeight: 120, ratio: nftImage.ratio) - }, - bind: { cell, _ in - cell.bind(nftImage: nftImage, cornerRadius: .cornerRadius8) - } - ) - ] + id: "image", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin12), + rows: [ + Row( + id: "image", + dynamicHeight: { width in + NftAssetImageCell.height(containerWidth: width, maxHeight: 120, ratio: nftImage.ratio) + }, + bind: { cell, _ in + cell.bind(nftImage: nftImage, cornerRadius: .cornerRadius8) + } + ), + ] ) } @@ -143,62 +142,61 @@ extension SendEip721ViewController: SectionsDataSource { let name = viewModel.name sections.append( - Section( - id: "title", - rows: [ - CellBuilderNew.row( - rootElement: .text { component in - component.font = nameFont - component.textColor = .themeLeah - component.text = name - component.numberOfLines = 0 - component.textAlignment = .center - }, - tableView: tableView, - id: "name", - dynamicHeight: { width in - CellBuilderNew.height( - containerWidth: width, - backgroundStyle: .transparent, - text: name, - font: nameFont, - verticalPadding: .margin12, - elements: [.multiline] - ) - }, - bind: { cell in - cell.set(backgroundStyle: .transparent, isFirst: true) - } + Section( + id: "title", + rows: [ + CellBuilderNew.row( + rootElement: .text { component in + component.font = nameFont + component.textColor = .themeLeah + component.text = name + component.numberOfLines = 0 + component.textAlignment = .center + }, + tableView: tableView, + id: "name", + dynamicHeight: { width in + CellBuilderNew.height( + containerWidth: width, + backgroundStyle: .transparent, + text: name, + font: nameFont, + verticalPadding: .margin12, + elements: [.multiline] ) - ] - ) + }, + bind: { cell in + cell.set(backgroundStyle: .transparent, isFirst: true) + } + ), + ] + ) ) sections.append( - Section( - id: "recipient", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: recipientCell, - id: "recipient-input", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "recipient-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + Section( + id: "recipient", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: recipientCell, + id: "recipient-input", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: recipientCautionCell, + id: "recipient-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ) ) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewModel.swift index f29be13d96..95b0abc854 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/Eip721/SendEip721ViewModel.swift @@ -1,7 +1,7 @@ -import RxSwift -import RxCocoa import EvmKit import MarketKit +import RxCocoa +import RxSwift class SendEip721ViewModel { private let service: SendEip721Service @@ -24,11 +24,9 @@ class SendEip721ViewModel { proceedEnabledRelay.accept(false) } } - } extension SendEip721ViewModel { - var proceedEnableDriver: Driver { proceedEnabledRelay.asDriver() } @@ -46,11 +44,10 @@ extension SendEip721ViewModel { } func didTapProceed() { - guard case .ready(let sendData) = service.state else { + guard case let .ready(sendData) = service.state else { return } proceedRelay.accept(sendData) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/SendNftModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/SendNftModule.swift index 0b0b6ac385..6ae6589f8f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/SendNftModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendNft/SendNftModule.swift @@ -1,19 +1,19 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit class SendNftModule { - private static func addressService(blockchainType: BlockchainType) -> AddressService { let evmAddressParserItem = EvmAddressParser() let udnAddressParserItem = UdnAddressParserItem.item(rawAddressParserItem: evmAddressParserItem, blockchainType: blockchainType) let addressParserChain = AddressParserChain() - .append(handler: evmAddressParserItem) - .append(handler: udnAddressParserItem) + .append(handler: evmAddressParserItem) + .append(handler: udnAddressParserItem) if let httpSyncSource = App.shared.evmSyncSourceManager.httpSyncSource(blockchainType: .ethereum), - let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) { + let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) + { addressParserChain.append(handler: ensAddressParserItem) } @@ -61,8 +61,9 @@ class SendNftModule { let evmBlockchainManager = App.shared.evmBlockchainManager guard let evmKitWrapper = try? evmBlockchainManager - .evmKitManager(blockchainType: nftUid.blockchainType) - .evmKitWrapper(account: account, blockchainType: nftUid.blockchainType) else { + .evmKitManager(blockchainType: nftUid.blockchainType) + .evmKitWrapper(account: account, blockchainType: nftUid.blockchainType) + else { return nil } @@ -87,5 +88,4 @@ class SendNftModule { return ThemeNavigationController(rootViewController: viewController) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationModule.swift index eab835da59..33b226bfa2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationModule.swift @@ -1,12 +1,11 @@ import Foundation -import UIKit +import HsExtensions +import MarketKit import ThemeKit import TronKit -import MarketKit -import HsExtensions +import UIKit struct SendTronConfirmationModule { - static func viewController(tronKitWrapper: TronKitWrapper, contract: Contract) -> UIViewController? { guard let coinServiceFactory = EvmCoinServiceFactory( blockchainType: .tron, @@ -29,5 +28,4 @@ struct SendTronConfirmationModule { return controller } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationService.swift index 2ad8366b02..fdfdc81c62 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationService.swift @@ -1,10 +1,10 @@ +import BigInt +import Combine import Foundation -import RxSwift +import HsExtensions import RxCocoa +import RxSwift import TronKit -import BigInt -import HsExtensions -import Combine class SendTronConfirmationService { private var tasks = Set() @@ -60,17 +60,17 @@ class SendTronConfirmationService { ) switch contract { - case let transfer as TransferContract: - sendAddress = transfer.toAddress - - case is TriggerSmartContract: - if let transfer = dataState.decoration as? OutgoingEip20Decoration { - sendAddress = transfer.to - } else { - sendAddress = nil - } + case let transfer as TransferContract: + sendAddress = transfer.toAddress + + case is TriggerSmartContract: + if let transfer = dataState.decoration as? OutgoingEip20Decoration { + sendAddress = transfer.to + } else { + sendAddress = nil + } - default: sendAddress = nil + default: sendAddress = nil } feeService.feeValueService = self @@ -102,11 +102,11 @@ class SendTronConfirmationService { var totalFees = 0 for fee in fees { switch fee { - case .bandwidth(let points, let price): + case let .bandwidth(points, price): totalFees += points * price - case .energy(let required, let price): + case let .energy(required, price): totalFees += required * price - case .accountActivation(let amount): + case let .accountActivation(amount): totalFees += amount } } @@ -145,7 +145,7 @@ class SendTronConfirmationService { } private func syncAddress() { - guard let sendAddress = sendAddress else { + guard let sendAddress else { return } @@ -154,20 +154,15 @@ class SendTronConfirmationService { self?.sendAdressActive = active ?? true }.store(in: &tasks) } - } extension SendTronConfirmationService: ISendXFeeValueService { - var feeStateObservable: Observable> { feeStateRelay.asObservable() } - - } extension SendTronConfirmationService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -198,11 +193,9 @@ extension SendTronConfirmationService { } }.store(in: &tasks) } - } extension SendTronConfirmationService { - enum State { case ready(fees: [Fee]) case notReady(errors: [Error]) @@ -224,5 +217,4 @@ extension SendTronConfirmationService { case insufficientBalance(balance: BigUInt) case zeroAmount } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewController.swift index f27ff30ad2..ddd58b1755 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewController.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit import Foundation import MarketKit +import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class SendTronConfirmationViewController: ThemeViewController { let disposeBag = DisposeBag() @@ -34,7 +34,8 @@ class SendTronConfirmationViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -100,12 +101,11 @@ class SendTronConfirmationViewController: ThemeViewController { } private func handleFeeItems(items: [SendTronConfirmationViewModel.TronFeeViewItem]) { - self.feeViewItems = items + feeViewItems = items reloadTable() } - func handleSending() { - } + func handleSending() {} func handleSendSuccess() { dismiss(animated: true) @@ -136,27 +136,27 @@ class SendTronConfirmationViewController: ThemeViewController { private func row(viewItem: SendTronConfirmationViewModel.ViewItem, rowInfo: RowInfo) -> RowProtocol { switch viewItem { - case let .subhead(iconName, title, value): - return CellComponent.actionTitleRow(tableView: tableView, rowInfo: rowInfo, iconName: iconName, iconDimmed: true, title: title, value: value) - case let .amount(iconUrl, iconPlaceholderImageName, coinAmount, currencyAmount, type): - return CellComponent.amountRow(tableView: tableView, rowInfo: rowInfo, iconUrl: iconUrl, iconPlaceholderImageName: iconPlaceholderImageName, coinAmount: coinAmount, currencyAmount: currencyAmount, type: type) - case let .address(title, value, valueTitle, contactAddress): - var onAddToContact: (() -> ())? = nil - if let contactAddress { - onAddToContact = { [weak self] in - ContactBookModule.showAddition(contactAddress: contactAddress, parentViewController: self) - } + case let .subhead(iconName, title, value): + return CellComponent.actionTitleRow(tableView: tableView, rowInfo: rowInfo, iconName: iconName, iconDimmed: true, title: title, value: value) + case let .amount(iconUrl, iconPlaceholderImageName, coinAmount, currencyAmount, type): + return CellComponent.amountRow(tableView: tableView, rowInfo: rowInfo, iconUrl: iconUrl, iconPlaceholderImageName: iconPlaceholderImageName, coinAmount: coinAmount, currencyAmount: currencyAmount, type: type) + case let .address(title, value, valueTitle, contactAddress): + var onAddToContact: (() -> Void)? = nil + if let contactAddress { + onAddToContact = { [weak self] in + ContactBookModule.showAddition(contactAddress: contactAddress, parentViewController: self) } - return CellComponent.fromToRow(tableView: tableView, rowInfo: rowInfo, title: title, value: value, valueTitle: valueTitle, onAddToContact: onAddToContact) - case let .value(title, value, type): - return CellComponent.valueRow(tableView: tableView, rowInfo: rowInfo, iconName: nil, title: title, value: value, type: type) - case let .warning(text, title, info): - return warningRow(tableView: tableView, rowInfo: rowInfo, text: text, title: title, info: info) + } + return CellComponent.fromToRow(tableView: tableView, rowInfo: rowInfo, title: title, value: value, valueTitle: valueTitle, onAddToContact: onAddToContact) + case let .value(title, value, type): + return CellComponent.valueRow(tableView: tableView, rowInfo: rowInfo, iconName: nil, title: title, value: value, type: type) + case let .warning(text, title, info): + return warningRow(tableView: tableView, rowInfo: rowInfo, text: text, title: title, info: info) } } private func section(sectionViewItem: SendTronConfirmationViewModel.SectionViewItem, index: Int) -> SectionProtocol { - return Section( + Section( id: "section_\(index)", headerState: .margin(height: .margin12), rows: sectionViewItem.viewItems.enumerated().map { index, viewItem in @@ -195,30 +195,30 @@ class SendTronConfirmationViewController: ThemeViewController { return CellBuilderNew.row( rootElement: .hStack([ - .secondaryButton { [weak self] component in - component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) - component.button.setTitle(item.title, for: .normal) - component.onTap = { [weak self] in - self?.openInfo(title: item.title, description: item.info) - } - }, - .margin0, - .text { _ in }, - .vStackCentered([ - .text { (component: TextComponent) -> () in + .secondaryButton { [weak self] component in + component.button.set(style: .transparent2, image: UIImage(named: "circle_information_20")) + component.button.setTitle(item.title, for: .normal) + component.onTap = { [weak self] in + self?.openInfo(title: item.title, description: item.info) + } + }, + .margin0, + .text { _ in }, + .vStackCentered([ + .text { (component: TextComponent) in component.font = .subhead2 component.textColor = .themeLeah component.textAlignment = .right component.text = item.value1 }, .margin(1), - .text { (component: TextComponent) -> () in + .text { (component: TextComponent) in component.font = value2Font component.textColor = value2Color component.textAlignment = .right component.text = item.value2 - } - ]) + }, + ]), ]), tableView: tableView, id: "double-amount-\(rowInfo.index)", @@ -229,11 +229,9 @@ class SendTronConfirmationViewController: ThemeViewController { } ) } - } extension SendTronConfirmationViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { let transactionSections: [SectionProtocol] = sectionViewItems.enumerated().map { index, sectionViewItem in section(sectionViewItem: sectionViewItem, index: index) @@ -269,12 +267,11 @@ extension SendTronConfirmationViewController: SectionsDataSource { dynamicHeight: { [weak self] containerWidth in self?.cautionCell.cellHeight(containerWidth: containerWidth) ?? 0 } - ) + ), ] - ) + ), ] return transactionSections + feeSections + cautionsSections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewModel.swift index de679b71a9..13fbe2c328 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/Confirmation/SendTronConfirmationViewModel.swift @@ -1,10 +1,10 @@ +import BigInt import Foundation -import RxSwift +import HsExtensions +import MarketKit import RxCocoa +import RxSwift import TronKit -import BigInt -import MarketKit -import HsExtensions class SendTronConfirmationViewModel { private let disposeBag = DisposeBag() @@ -19,7 +19,7 @@ class SendTronConfirmationViewModel { private let sendEnabledRelay = BehaviorRelay(value: false) private let cautionsRelay = BehaviorRelay<[TitledCaution]>(value: []) - private let sendingRelay = PublishRelay<()>() + private let sendingRelay = PublishRelay() private let sendSuccessRelay = PublishRelay() private let sendFailedRelay = PublishRelay() @@ -46,45 +46,45 @@ class SendTronConfirmationViewModel { private func sync(state: SendTronConfirmationService.State) { switch state { - case .ready(let fees): - feesRelay.accept(feeItems(fees: fees)) - sendEnabledRelay.accept(true) - cautionsRelay.accept([]) - - case .notReady(let errors): - feesRelay.accept([]) - sendEnabledRelay.accept(false) - - let cautions = errors.map { error in - if let tronError = error as? SendTronConfirmationService.TransactionError { - switch tronError { - case .insufficientBalance(let balance): - let coinValue = coinServiceFactory.baseCoinService.coinValue(value: balance) - let balanceString = ValueFormatter.instance.formatShort(coinValue: coinValue) - - return TitledCaution( - title: "fee_settings.errors.insufficient_balance".localized, - text: "fee_settings.errors.insufficient_balance.info".localized(balanceString ?? ""), - type: .error - ) - - case .zeroAmount: - return TitledCaution( - title: "alert.error".localized, - text: "fee_settings.errors.zero_amount.info".localized, - type: .error - ) - } - } else { + case let .ready(fees): + feesRelay.accept(feeItems(fees: fees)) + sendEnabledRelay.accept(true) + cautionsRelay.accept([]) + + case let .notReady(errors): + feesRelay.accept([]) + sendEnabledRelay.accept(false) + + let cautions = errors.map { error in + if let tronError = error as? SendTronConfirmationService.TransactionError { + switch tronError { + case let .insufficientBalance(balance): + let coinValue = coinServiceFactory.baseCoinService.coinValue(value: balance) + let balanceString = ValueFormatter.instance.formatShort(coinValue: coinValue) + + return TitledCaution( + title: "fee_settings.errors.insufficient_balance".localized, + text: "fee_settings.errors.insufficient_balance.info".localized(balanceString ?? ""), + type: .error + ) + + case .zeroAmount: return TitledCaution( - title: "Error", - text: error.convertedError.smartDescription, + title: "alert.error".localized, + text: "fee_settings.errors.zero_amount.info".localized, type: .error ) } + } else { + return TitledCaution( + title: "Error", + text: error.convertedError.smartDescription, + type: .error + ) } + } - cautionsRelay.accept(cautions) + cautionsRelay.accept(cautions) } sectionViewItemsRelay.accept(items(dataState: service.dataState)) @@ -100,10 +100,10 @@ class SendTronConfirmationViewModel { private func sync(sendState: SendTronConfirmationService.SendState) { switch sendState { - case .idle: () - case .sending: sendingRelay.accept(()) - case .sent: sendSuccessRelay.accept(()) - case .failed(let error): sendFailedRelay.accept(error.convertedError.smartDescription) + case .idle: () + case .sending: sendingRelay.accept(()) + case .sent: sendSuccessRelay.accept(()) + case let .failed(error): sendFailedRelay.accept(error.convertedError.smartDescription) } } @@ -115,7 +115,7 @@ class SendTronConfirmationViewModel { for fee in fees { switch fee { - case .accountActivation(let amount): + case let .accountActivation(amount): let amountData = coinService.amountData(value: BigUInt(amount)) viewItems.append( @@ -128,11 +128,11 @@ class SendTronConfirmationViewModel { ) ) - case .bandwidth(let points, _): - bandwidth = ValueFormatter.instance.formatShort(value: Decimal(points), decimalCount: 0) + case let .bandwidth(points, _): + bandwidth = ValueFormatter.instance.formatShort(value: Decimal(points), decimalCount: 0) - case .energy(let required, _): - energy = ValueFormatter.instance.formatShort(value: Decimal(required), decimalCount: 0) + case let .energy(required, _): + energy = ValueFormatter.instance.formatShort(value: Decimal(required), decimalCount: 0) } } @@ -152,34 +152,34 @@ class SendTronConfirmationViewModel { } private func items(dataState: SendTronConfirmationService.DataState) -> [SectionViewItem] { - if let decoration = dataState.decoration, let items = self.items(decoration: decoration, contract: dataState.contract) { + if let decoration = dataState.decoration, let items = items(decoration: decoration, contract: dataState.contract) { return items } return [] } - private func items(decoration: TransactionDecoration, contract: Contract?) -> [SectionViewItem]? { + private func items(decoration: TransactionDecoration, contract _: Contract?) -> [SectionViewItem]? { switch decoration { - case let decoration as NativeTransactionDecoration: - guard let transfer = decoration.contract as? TransferContract else { - return nil - } + case let decoration as NativeTransactionDecoration: + guard let transfer = decoration.contract as? TransferContract else { + return nil + } - return sendBaseCoinItems( - to: transfer.toAddress, - value: BigUInt(transfer.amount) - ) + return sendBaseCoinItems( + to: transfer.toAddress, + value: BigUInt(transfer.amount) + ) - case let decoration as OutgoingEip20Decoration: - return eip20TransferItems( - to: decoration.to, - value: decoration.value, - contractAddress: decoration.contractAddress - ) + case let decoration as OutgoingEip20Decoration: + return eip20TransferItems( + to: decoration.to, + value: decoration.value, + contractAddress: decoration.contractAddress + ) - default: - return nil + default: + return nil } } @@ -189,7 +189,7 @@ class SendTronConfirmationViewModel { } return [ - .warning(text: "tron.send.inactive_address".localized, title: "tron.send.activation_fee".localized, info: "tron.send.activation_fee.info".localized) + .warning(text: "tron.send.inactive_address".localized, title: "tron.send.activation_fee".localized, info: "tron.send.activation_fee.info".localized), ] } @@ -272,7 +272,7 @@ class SendTronConfirmationViewModel { coinService: coinService, value: value, type: .neutral - ) + ), ] let addressValue = to.base58 @@ -297,11 +297,9 @@ class SendTronConfirmationViewModel { private func coinService(token: MarketKit.Token) -> CoinService { coinServiceFactory.coinService(token: token) } - } extension SendTronConfirmationViewModel { - var sectionViewItemsDriver: Driver<[SectionViewItem]> { sectionViewItemsRelay.asDriver() } @@ -318,7 +316,7 @@ extension SendTronConfirmationViewModel { cautionsRelay.asDriver() } - var sendingSignal: Signal<()> { + var sendingSignal: Signal { sendingRelay.asSignal() } @@ -333,11 +331,9 @@ extension SendTronConfirmationViewModel { func send() { service.send() } - } extension SendTronConfirmationViewModel { - struct SectionViewItem { let viewItems: [ViewItem] } @@ -357,5 +353,4 @@ extension SendTronConfirmationViewModel { let value2: String? let value2IsSecondary: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronModule.swift index 8997b454c0..ae451e539b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronModule.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit class SendTronModule { - static func viewController(token: Token, mode: SendBaseService.Mode, adapter: ISendTronAdapter) -> UIViewController { let tronAddressParserItem = TronAddressParser() let addressParserChain = AddressParserChain().append(handler: tronAddressParserItem) @@ -46,5 +45,4 @@ class SendTronModule { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronService.swift index 1fdcc1b106..9137c67b31 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronService.swift @@ -1,10 +1,10 @@ +import BigInt import Foundation +import HsExtensions import MarketKit -import RxSwift import RxRelay +import RxSwift import TronKit -import BigInt -import HsExtensions class SendTronService { let sendToken: Token @@ -32,7 +32,7 @@ class SendTronService { } private let addressErrorRelay = PublishRelay() - private var addressError: Error? = nil { + private var addressError: Error? { didSet { addressErrorRelay.accept(addressError) } @@ -47,10 +47,10 @@ class SendTronService { self.addressService = addressService switch mode { - case .prefilled(let address, let amount): + case let .prefilled(address, amount): addressService.set(text: address) if let amount { addressService.publishAmountRelay.accept(amount) } - case .predefined(let address): addressService.set(text: address) + case let .predefined(address): addressService.set(text: address) case .send: () } @@ -59,20 +59,20 @@ class SendTronService { private func sync(addressState: AddressService.State) { switch addressState { - case .success(let address): - do { - addressData = AddressData(tronAddress: try TronKit.Address(address: address.raw), domain: address.domain) - } catch { - addressData = nil - } - default: addressData = nil + case let .success(address): + do { + addressData = try AddressData(tronAddress: TronKit.Address(address: address.raw), domain: address.domain) + } catch { + addressData = nil + } + default: addressData = nil } syncState() } private func syncState() { - if amountCaution.error == nil, case .success = addressService.state, let tronAmount = tronAmount, let addressData = addressData { + if amountCaution.error == nil, case .success = addressService.state, let tronAmount, let addressData { let contract = adapter.contract(amount: tronAmount, address: addressData.tronAddress) state = .ready(contract: contract) } else { @@ -91,11 +91,9 @@ class SendTronService { return tronAmount } - } extension SendTronService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -111,11 +109,9 @@ extension SendTronService { var activeAddressObservable: Observable { activeAddressRelay.asObservable() } - } extension SendTronService: IAvailableBalanceService { - var availableBalance: DataStatus { .completed(adapter.balanceData.available) } @@ -123,11 +119,9 @@ extension SendTronService: IAvailableBalanceService { var availableBalanceObservable: Observable> { Observable.just(availableBalance) } - } extension SendTronService: IAmountInputService { - var amount: Decimal { 0 } @@ -160,8 +154,8 @@ extension SendTronService: IAmountInputService { var amountWarning: AmountWarning? = nil if amount.isEqual(to: adapter.balanceData.available) { switch sendToken.type { - case .native: amountWarning = AmountWarning.coinNeededForFee - default: () + case .native: amountWarning = AmountWarning.coinNeededForFee + default: () } } @@ -207,11 +201,9 @@ extension SendTronService: IAmountInputService { }) .disposed(by: disposeBag) } - } extension SendTronService { - enum State { case ready(contract: TronKit.Contract) case notReady @@ -234,5 +226,4 @@ extension SendTronService { let tronAddress: TronKit.Address let domain: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewController.swift index 71a9dbf0b1..ceb88a23e5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView -import RxSwift import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit import TronKit +import UIKit class SendTronViewController: ThemeViewController { private let tronKitWrapper: TronKitWrapper @@ -41,7 +41,8 @@ class SendTronViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -138,11 +139,9 @@ class SendTronViewController: ThemeViewController { } navigationController?.pushViewController(viewController, animated: true) } - } extension SendTronViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [ Section( @@ -153,7 +152,7 @@ extension SendTronViewController: SectionsDataSource { cell: availableBalanceCell, id: "available-balance", height: availableBalanceCell.cellHeight - ) + ), ] ), Section( @@ -171,48 +170,47 @@ extension SendTronViewController: SectionsDataSource { dynamicHeight: { [weak self] width in self?.amountCautionCell.height(containerWidth: width) ?? 0 } - ) + ), ] - ) + ), ] if viewModel.showAddress { sections.append( - Section( - id: "recipient", - headerState: .margin(height: .margin16), - rows: [ - StaticRow( - cell: recipientCell, - id: "recipient-input", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "recipient-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + Section( + id: "recipient", + headerState: .margin(height: .margin16), + rows: [ + StaticRow( + cell: recipientCell, + id: "recipient-input", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: recipientCautionCell, + id: "recipient-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] + ) ) } sections.append( - Section( + Section( + id: "button", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: buttonCell, id: "button", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: buttonCell, - id: "button", - height: PrimaryButtonCell.height - ) - ] - ) + height: PrimaryButtonCell.height + ), + ] + ) ) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewModel.swift index 8e00c834bd..f007e15c0a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/SendTronViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift +import MarketKit import RxCocoa +import RxSwift import TronKit -import MarketKit class SendTronViewModel { private let service: SendTronService @@ -32,13 +32,13 @@ class SendTronViewModel { } private func sync(amountCaution: (error: Error?, warning: SendTronService.AmountWarning?)) { - var caution: Caution? = nil + var caution: Caution? if let error = amountCaution.error { caution = Caution(text: error.smartDescription, type: .error) } else if let warning = amountCaution.warning { switch warning { - case .coinNeededForFee: caution = Caution(text: "send.amount_warning.coin_needed_for_fee".localized(service.sendToken.coin.code), type: .warning) + case .coinNeededForFee: caution = Caution(text: "send.amount_warning.coin_needed_for_fee".localized(service.sendToken.coin.code), type: .warning) } } @@ -46,7 +46,7 @@ class SendTronViewModel { } private func sync(addressError: Error?) { - var caution: Caution? = nil + var caution: Caution? if let error = addressError { caution = Caution(text: error.smartDescription, type: .error) @@ -54,11 +54,9 @@ class SendTronViewModel { addressCautionRelay.accept(caution) } - } extension SendTronViewModel { - var title: String { switch service.mode { case .send, .prefilled: return "send.title".localized(token.coin.code) @@ -94,32 +92,27 @@ extension SendTronViewModel { } func didTapProceed() { - guard case .ready(let sendData) = service.state else { + guard case let .ready(sendData) = service.state else { return } proceedRelay.accept(sendData) } - } extension SendTronService.AmountError: LocalizedError { - var errorDescription: String? { switch self { - case .insufficientBalance: return "send.amount_error.balance".localized - default: return "\(self)" + case .insufficientBalance: return "send.amount_error.balance".localized + default: return "\(self)" } } - } extension SendTronService.AddressError: LocalizedError { - var errorDescription: String? { switch self { - case .ownAddress: return "send.address_error.own_address".localized + case .ownAddress: return "send.address_error.own_address".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/TronRecipientAddressViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/TronRecipientAddressViewModel.swift index 358ed2ecfb..0ceeb1dea7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/TronRecipientAddressViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SendTron/TronRecipientAddressViewModel.swift @@ -26,6 +26,4 @@ class TronRecipientAddressViewModel: RecipientAddressViewModel { sendService.sync(address: address.raw) } } - } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupAppViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupAppViewModel.swift index 05656a3542..679a9f9670 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupAppViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupAppViewModel.swift @@ -59,6 +59,7 @@ class BackupAppViewModel: ObservableObject { validateName() } } + @Published var passwordPushed = false { didSet { // need to reset future fields: @@ -124,7 +125,7 @@ extension BackupAppViewModel { private var accountIds: [String] { accounts(watch: false) - .map { $0.id } + .map(\.id) } private func item(account: Account) -> BackupAppModule.AccountItem { @@ -153,10 +154,10 @@ extension BackupAppViewModel { let contacts = contactManager.all ?? [] return BackupAppModule.items( - watchAccountCount: accounts(watch: true).count, - watchlistCount: favoritesManager.allCoinUids.count, - contactAddressCount: contacts.count, - blockchainSourcesCount: evmSyncSourceManager.customSyncSources(blockchainType: nil).count + watchAccountCount: accounts(watch: true).count, + watchlistCount: favoritesManager.allCoinUids.count, + contactAddressCount: contacts.count, + blockchainSourcesCount: evmSyncSourceManager.customSyncSources(blockchainType: nil).count ) } @@ -183,8 +184,8 @@ extension BackupAppViewModel { switch destination { case .cloud: return RestoreFileHelper.resolve( - name: Self.backupNamePrefix, - elements: cloudBackupManager.existFilenames + name: Self.backupNamePrefix, + elements: cloudBackupManager.existFilenames ) default: return Self.backupNamePrefix @@ -240,12 +241,12 @@ extension BackupAppViewModel { func onTapSave() { validatePasswords() - guard passwordCautionState == .none && confirmCautionState == .none else { + guard passwordCautionState == .none, confirmCautionState == .none else { return } passwordButtonProcessing = true - let selectedIds = accountIds.filter { (selected[$0] ?? false) } + accounts(watch: true).map { $0.id } + let selectedIds = accountIds.filter { selected[$0] ?? false } + accounts(watch: true).map(\.id) Task { switch destination { case .none: () diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupPassword/BackupPasswordView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupPassword/BackupPasswordView.swift index e3b34103e3..9bc41fae79 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupPassword/BackupPasswordView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Backup/BackupPassword/BackupPasswordView.swift @@ -4,7 +4,7 @@ import ThemeKit struct BackupPasswordView: View { @ObservedObject var viewModel: BackupAppViewModel - var onDismiss: (() -> ())? + var onDismiss: (() -> Void)? @State var secureLock = true diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupAppModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupAppModule.swift index d474139e49..c4b95e3458 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupAppModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupAppModule.swift @@ -1,13 +1,13 @@ import SwiftUI struct BackupAppModule { - static func view(onDismiss: (() -> ())?) -> some View { + static func view(onDismiss: (() -> Void)?) -> some View { let viewModel = BackupAppViewModel( - accountManager: App.shared.accountManager, - contactManager: App.shared.contactManager, - cloudBackupManager: App.shared.cloudBackupManager, - favoritesManager: App.shared.favoritesManager, - evmSyncSourceManager: App.shared.evmSyncSourceManager + accountManager: App.shared.accountManager, + contactManager: App.shared.contactManager, + cloudBackupManager: App.shared.cloudBackupManager, + favoritesManager: App.shared.favoritesManager, + evmSyncSourceManager: App.shared.evmSyncSourceManager ) return BackupTypeView(viewModel: viewModel, onDismiss: onDismiss) @@ -27,17 +27,17 @@ extension BackupAppModule { switch self { case .cloud: return BackupDestinationDisclaimer( - title: "backup_app.backup.disclaimer.cloud.title".localized, - highlightedDescription: "backup_app.backup.disclaimer.cloud.description".localized, - selectedCheckboxText: "backup_app.backup.disclaimer.cloud.checkbox_label".localized, - buttonTitle: "button.next".localized + title: "backup_app.backup.disclaimer.cloud.title".localized, + highlightedDescription: "backup_app.backup.disclaimer.cloud.description".localized, + selectedCheckboxText: "backup_app.backup.disclaimer.cloud.checkbox_label".localized, + buttonTitle: "button.next".localized ) case .local: return BackupDestinationDisclaimer( - title: "backup_app.backup.disclaimer.file.title".localized, - highlightedDescription: "backup_app.backup.disclaimer.file.description".localized, - selectedCheckboxText: "backup_app.backup.disclaimer.file.checkbox_label".localized, - buttonTitle: "button.next".localized + title: "backup_app.backup.disclaimer.file.title".localized, + highlightedDescription: "backup_app.backup.disclaimer.file.description".localized, + selectedCheckboxText: "backup_app.backup.disclaimer.file.checkbox_label".localized, + buttonTitle: "button.next".localized ) } } @@ -57,40 +57,40 @@ extension BackupAppModule { if watchAccountCount != 0 { items.append(BackupAppModule.Item( - title: "backup_app.backup_list.other.watch_account.title".localized, - value: watchAccountCount.description + title: "backup_app.backup_list.other.watch_account.title".localized, + value: watchAccountCount.description )) } if watchlistCount != 0 { items.append(BackupAppModule.Item( - title: "backup_app.backup_list.other.watchlist.title".localized, - value: watchlistCount.description + title: "backup_app.backup_list.other.watchlist.title".localized, + value: watchlistCount.description )) } if contactAddressCount != 0 { items.append(BackupAppModule.Item( - title: "backup_app.backup_list.other.contacts.title".localized, - value: contactAddressCount.description + title: "backup_app.backup_list.other.contacts.title".localized, + value: contactAddressCount.description )) } if blockchainSourcesCount != 0 { items.append(BackupAppModule.Item( - title: "backup_app.backup_list.other.blockchain_settings.title".localized, - value: blockchainSourcesCount.description + title: "backup_app.backup_list.other.blockchain_settings.title".localized, + value: blockchainSourcesCount.description )) } items.append(BackupAppModule.Item( - title: "backup_app.backup_list.other.app_settings.title".localized, - description: "backup_app.backup_list.other.app_settings.description".localized + title: "backup_app.backup_list.other.app_settings.title".localized, + description: "backup_app.backup_list.other.app_settings.description".localized )) return items } - } + extension BackupAppModule { struct AccountItem: Comparable, Identifiable { let accountId: String @@ -126,4 +126,4 @@ extension BackupAppModule { title } } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupManagerLegacy/BackupManagerViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupManagerLegacy/BackupManagerViewController.swift index a3cc11376e..9644e40c22 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupManagerLegacy/BackupManagerViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/BackupManagerLegacy/BackupManagerViewController.swift @@ -41,13 +41,13 @@ class BackupManagerViewController: ThemeViewController { viewModel .openUnlockPublisher .receive(on: DispatchQueue.main) - .sink(receiveValue: { [weak self] event in self?.onUnlock() }) + .sink(receiveValue: { [weak self] _ in self?.onUnlock() }) .store(in: &cancellables) viewModel .openBackupPublisher .receive(on: DispatchQueue.main) - .sink(receiveValue: { [weak self] event in self?.onCreate() }) + .sink(receiveValue: { [weak self] _ in self?.onCreate() }) .store(in: &cancellables) tableView.buildSections() @@ -65,8 +65,8 @@ class BackupManagerViewController: ThemeViewController { private func onUnlock() { let viewController = UnlockModule.moduleUnlockView { [weak self] in - self?.viewModel.unlock() - }.toNavigationViewController() + self?.viewModel.unlock() + }.toNavigationViewController() present(viewController, animated: true) } @@ -77,7 +77,7 @@ class BackupManagerViewController: ThemeViewController { self?.presentedViewController?.dismiss(animated: true) }.toNavigationViewController() - self.present(viewController, animated: true) + present(viewController, animated: true) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Restore/RestoreAppViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Restore/RestoreAppViewModel.swift index 765ce98adc..3719647d6f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Restore/RestoreAppViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BackupApp/Restore/RestoreAppViewModel.swift @@ -8,6 +8,4 @@ class RestoreAppViewModel { } } -extension RestoreAppViewModel { - -} \ No newline at end of file +extension RestoreAppViewModel {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BaseCurrency/BaseCurrencySettingsView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BaseCurrency/BaseCurrencySettingsView.swift index 8bf7889f74..dc0e06b85c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BaseCurrency/BaseCurrencySettingsView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BaseCurrency/BaseCurrencySettingsView.swift @@ -42,7 +42,7 @@ struct BaseCurrencySettingsView: View { .padding(.horizontal, .margin32) .padding(.vertical, .margin24) - HighlightedTextView(text: "settings.base_currency.disclaimer.description".localized(AppConfig.appName, viewModel.popularCurrencies.map { $0.code }.joined(separator: ","))) + HighlightedTextView(text: "settings.base_currency.disclaimer.description".localized(AppConfig.appName, viewModel.popularCurrencies.map(\.code).joined(separator: ","))) .padding(.horizontal, .margin16) VStack(spacing: .margin12) { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BlockchainSettings/BlockchainSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BlockchainSettings/BlockchainSettingsViewModel.swift index 773a346b35..bcf309202f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BlockchainSettings/BlockchainSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/BlockchainSettings/BlockchainSettingsViewModel.swift @@ -57,9 +57,9 @@ struct BtcSyncModeItem { var title: String { switch restoreMode { - case .blockchair: return "Blockchair API" - case .hybrid: return "sync_mode.hybrid".localized - case .blockchain: return "sync_mode.from_blockchain".localized(blockchain.name) + case .blockchair: return "Blockchair API" + case .hybrid: return "sync_mode.hybrid".localized + case .blockchain: return "sync_mode.from_blockchain".localized(blockchain.name) } } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressModule.swift index c669b336d2..943976b642 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressModule.swift @@ -1,10 +1,8 @@ import UIKit class DonateAddressModule { - static var viewController: UIViewController { let viewModel = DonateAddressViewModel(marketKit: App.shared.marketKit) return DonateAddressViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewController.swift index 5225575838..f7477e445b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SectionsTableView import ComponentKit import MarketKit +import SectionsTableView +import ThemeKit +import UIKit class DonateAddressViewController: ThemeViewController { private let viewModel: DonateAddressViewModel @@ -14,7 +14,8 @@ class DonateAddressViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -46,54 +47,51 @@ class DonateAddressViewController: ThemeViewController { private var addressSections: [SectionProtocol] { viewModel.viewItems - .sorted(by: { $0.1.order < $1.1.order }) - .enumerated().map { index, viewItem -> SectionProtocol in - Section( - id: "section-id-\(index)", - headerState: tableView.sectionHeader(text: viewItem.0), - footerState: .margin(height: .margin24), - rows: [ - CellBuilderNew.row( - rootElement: .hStack([ - .image32 { (component: ImageComponent) -> () in - component.setImage( - urlString: viewItem.1.imageUrl, - placeholder: UIImage(named: viewItem.1.placeholderImageName(tokenProtocol: .native)) - ) - }, - .text { component in - component.font = .subhead2 - component.textColor = .themeLeah - component.text = viewItem.2 - component.textAlignment = .right - component.numberOfLines = 0 - }, - .secondaryCircleButton { component in - component.button.set(image: UIImage(named: "copy_20")) - component.onTap = { - CopyHelper.copyAndNotify(value: viewItem.2) - } - } - ]), - tableView: tableView, - id: "donate-address-\(index)", - hash: "donate-address-hash-\(index)", - height: .heightCell56, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - } - ) - ] - ) - } + .sorted(by: { $0.1.order < $1.1.order }) + .enumerated().map { index, viewItem -> SectionProtocol in + Section( + id: "section-id-\(index)", + headerState: tableView.sectionHeader(text: viewItem.0), + footerState: .margin(height: .margin24), + rows: [ + CellBuilderNew.row( + rootElement: .hStack([ + .image32 { (component: ImageComponent) in + component.setImage( + urlString: viewItem.1.imageUrl, + placeholder: UIImage(named: viewItem.1.placeholderImageName(tokenProtocol: .native)) + ) + }, + .text { component in + component.font = .subhead2 + component.textColor = .themeLeah + component.text = viewItem.2 + component.textAlignment = .right + component.numberOfLines = 0 + }, + .secondaryCircleButton { component in + component.button.set(image: UIImage(named: "copy_20")) + component.onTap = { + CopyHelper.copyAndNotify(value: viewItem.2) + } + }, + ]), + tableView: tableView, + id: "donate-address-\(index)", + hash: "donate-address-hash-\(index)", + height: .heightCell56, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + } + ), + ] + ) + } } - } extension DonateAddressViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { addressSections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewModel.swift index 81bdd94c7a..837ff088dd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateAddressViewModel.swift @@ -21,5 +21,4 @@ class DonateAddressViewModel { self.viewItems = viewItems } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionCell.swift index 89cb1a6a3b..e312628fd1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionCell.swift @@ -38,18 +38,16 @@ class DonateDescriptionCell: UITableViewCell { emoji.textAlignment = .center } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension DonateDescriptionCell { - static func height(containerWidth: CGFloat, text: String, font: UIFont? = nil, ignoreBottomMargin: Bool = false) -> CGFloat { let textHeight = text.height(forContainerWidth: containerWidth - 2 * horizontalPadding, font: font ?? Self.labelFont) let emojiHeight = "🙏".height(forContainerWidth: containerWidth - 2 * horizontalPadding, font: font ?? Self.labelFont) return textHeight + .margin24 + emojiHeight + (ignoreBottomMargin ? 1 : 2) * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionDataSource.swift index 14b05f5186..787bd16e98 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Donate/DonateDescriptionDataSource.swift @@ -1,6 +1,6 @@ -import UIKit import ComponentKit import SectionsTableView +import UIKit class DonateDescriptionDataSource: NSObject, ISectionDataSource { weak var delegate: ISectionDataSourceDelegate? @@ -14,9 +14,9 @@ class DonateDescriptionDataSource: NSObject, ISectionDataSource { private let rootGetAddressElement: CellBuilderNew.CellElement = .hStack([ .textElement(text: .body("donate.list.get_address".localized)), .margin8, - .image20 { (component: ImageComponent) -> () in + .image20 { (component: ImageComponent) in component.imageView.image = UIImage(named: "arrow_big_forward_20")?.withTintColor(.themeGray) - } + }, ]) func prepare(tableView: UITableView) { @@ -25,11 +25,11 @@ class DonateDescriptionDataSource: NSObject, ISectionDataSource { tableView.registerCell(forClass: EmptyCell.self) } - func numberOfSections(in tableView: UITableView) -> Int { + func numberOfSections(in _: UITableView) -> Int { 1 } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { 3 } @@ -41,16 +41,16 @@ class DonateDescriptionDataSource: NSObject, ISectionDataSource { case 1: return tableView.dequeueReusableCell(withIdentifier: String(describing: EmptyCell.self), for: indexPath) default: return CellBuilderNew.preparedCell( - tableView: tableView, - indexPath: originalIndexPath, - selectable: true, - rootElement: rootGetAddressElement, - layoutMargins: UIEdgeInsets(top: 0, left: .margin16, bottom: 0, right: .margin16) + tableView: tableView, + indexPath: originalIndexPath, + selectable: true, + rootElement: rootGetAddressElement, + layoutMargins: UIEdgeInsets(top: 0, left: .margin16, bottom: 0, right: .margin16) ) } } - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt _: IndexPath) { if let cell = cell as? DonateDescriptionCell { cell.label.text = "donate.support.description".localized } @@ -76,5 +76,4 @@ class DonateDescriptionDataSource: NSObject, ISectionDataSource { showAddresses() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsFooterCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsFooterCell.swift index 05c5d0ebd0..ae98c3e47c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsFooterCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsFooterCell.swift @@ -1,6 +1,6 @@ -import UIKit -import UIExtensions import SnapKit +import UIExtensions +import UIKit class MainSettingsFooterCell: UITableViewCell { let cellHeight: CGFloat = 130 @@ -8,7 +8,7 @@ class MainSettingsFooterCell: UITableViewCell { private let versionLabel = UILabel() private let logoButton = UIButton() - var onTapLogo: (() -> ())? + var onTapLogo: (() -> Void)? override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -58,7 +58,8 @@ class MainSettingsFooterCell: UITableViewCell { logoButton.addTarget(self, action: #selector(onTapLogoButton), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -69,5 +70,4 @@ class MainSettingsFooterCell: UITableViewCell { func set(appVersion: String) { versionLabel.text = "\(AppConfig.appName.uppercased()) \(appVersion)" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift index ea49ca1d5f..f9f8e5c890 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift @@ -3,7 +3,6 @@ import RxRelay import RxSwift import ThemeKit - class MainSettingsService { private let disposeBag = DisposeBag() @@ -96,7 +95,7 @@ extension MainSettingsService { } var walletConnectSessionCountObservable: Observable { - walletConnectSessionManager.sessionsObservable.map { $0.count } + walletConnectSessionManager.sessionsObservable.map(\.count) } var walletConnectPendingRequestCount: Int { @@ -104,7 +103,7 @@ extension MainSettingsService { } var walletConnectPendingRequestCountObservable: Observable { - walletConnectSessionManager.activePendingRequestsObservable.map { $0.count } + walletConnectSessionManager.activePendingRequestsObservable.map(\.count) } var currentLanguageDisplayName: String? { @@ -132,7 +131,7 @@ extension MainSettingsService { } var walletConnectState: WalletConnectState { - guard let activeAccount = activeAccount else { + guard let activeAccount else { return .noAccount } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportModule.swift index 4720aade29..86f2a43f0a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportModule.swift @@ -1,12 +1,10 @@ import UIKit struct PersonalSupportModule { - static func viewController() -> UIViewController { let localStorage = App.shared.localStorage let service = PersonalSupportService(marketKit: App.shared.marketKit, localStorage: localStorage) let viewModel = PersonalSupportViewModel(service: service) return PersonalSupportViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportService.swift index d1ec82f8c2..348798bcf6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportService.swift @@ -1,6 +1,6 @@ import Combine -import MarketKit import HsExtensions +import MarketKit class PersonalSupportService { private let marketKit: MarketKit.Kit @@ -35,11 +35,9 @@ class PersonalSupportService { requestButtonState = .enabled } - } extension PersonalSupportService { - var successPublisher: AnyPublisher { successSubject.eraseToAnyPublisher() } @@ -52,7 +50,7 @@ extension PersonalSupportService { self.username = username } - func request() { + func request() { guard let username else { return } @@ -76,5 +74,4 @@ extension PersonalSupportService { func newRequest() { requested = false } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewController.swift index be5e04e483..611cf99317 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewController.swift @@ -1,8 +1,8 @@ -import UIKit +import Combine +import ComponentKit import SectionsTableView import ThemeKit -import ComponentKit -import Combine +import UIKit class PersonalSupportViewController: KeyboardAwareViewController { private let viewModel: PersonalSupportViewModel @@ -23,7 +23,8 @@ class PersonalSupportViewController: KeyboardAwareViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -137,11 +138,9 @@ class PersonalSupportViewController: KeyboardAwareViewController { @objc private func onNewRequestTapped() { viewModel.onTapNewRequest() } - } extension PersonalSupportViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( @@ -152,10 +151,9 @@ extension PersonalSupportViewController: SectionsDataSource { StaticRow( cell: telegramUsernameCell, id: "telegram-username" - ) + ), ] ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewModel.swift index 6ae5a780d0..ed1366aa79 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/PersonalSupport/PersonalSupportViewModel.swift @@ -14,10 +14,10 @@ class PersonalSupportViewModel { self.service = service service.$requestButtonState - .sink { [weak self] state in - self?.sync(state: state) - } - .store(in: &cancellables) + .sink { [weak self] state in + self?.sync(state: state) + } + .store(in: &cancellables) subscribe(&cancellables, service.$requested) { [weak self] in self?.showRequestedScreenSubject.send($0) } @@ -42,11 +42,9 @@ class PersonalSupportViewModel { enabledRequestButtonSubject.send(requestButtonEnabled) hiddenRequestingButtonSubject.send(requestingButtonHidden) } - } extension PersonalSupportViewModel { - var showRequestedScreenPublisher: AnyPublisher { showRequestedScreenSubject.eraseToAnyPublisher() } @@ -84,5 +82,4 @@ extension PersonalSupportViewModel { func onTapNewRequest() { service.newRequest() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateModule.swift index fa8a508baa..3e4e6fc4ad 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateModule.swift @@ -1,16 +1,14 @@ import SwiftUI struct SimpleActivateModule { - static func bitcoinHodlingView() -> some View { let viewModel = SimpleActivateViewModel(localStorage: App.shared.localStorage) return SimpleActivateView( - viewModel: viewModel, - title: "settings.bitcoin_hodling.title".localized, - toggleText: "settings.bitcoin_hodling.lock_time".localized, - description: "settings.bitcoin_hodling.description".localized(AppConfig.appName, AppConfig.appName) + viewModel: viewModel, + title: "settings.bitcoin_hodling.title".localized, + toggleText: "settings.bitcoin_hodling.lock_time".localized, + description: "settings.bitcoin_hodling.description".localized(AppConfig.appName, AppConfig.appName) ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateViewModel.swift index b355dc1662..7d272795fe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/SimpleActivate/SimpleActivateViewModel.swift @@ -13,5 +13,4 @@ class SimpleActivateViewModel: ObservableObject { self.localStorage = localStorage activated = localStorage.lockTimeEnabled } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsService.swift index 57aac1f438..d111950c81 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsService.swift @@ -7,13 +7,10 @@ class TermsService { termsAccepted = termsManager.termsAccepted } - } extension TermsService { - func setTermsAccepted() { termsManager.setTermsAccepted() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewController.swift index feb63e1e43..2b10b33852 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import SnapKit -import RxSwift +import ComponentKit import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit import ThemeKit -import ComponentKit import UIExtensions -import SectionsTableView +import UIKit class TermsViewController: ThemeViewController { private let viewModel: TermsViewModel @@ -28,7 +28,8 @@ class TermsViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -94,17 +95,15 @@ class TermsViewController: ThemeViewController { tableView.reload(animated: true) } } - } extension TermsViewController: SectionsDataSource { - private func row(viewItem: TermsViewModel.ViewItem, index: Int, isFirst: Bool, isLast: Bool) -> RowProtocol { let backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence let textFont: UIFont = .subhead2 let text = viewItem.text - var action: (() -> ())? + var action: (() -> Void)? if viewModel.buttonVisible { action = { [weak self] in @@ -113,49 +112,48 @@ extension TermsViewController: SectionsDataSource { } return CellBuilderNew.row( - rootElement: .hStack([ - .image24 { component in - component.imageView.image = UIImage(named: viewItem.checked ? "checkbox_active_24" : "checkbox_diactive_24") - }, - .text { component in - component.font = textFont - component.textColor = .themeLeah - component.text = text - component.numberOfLines = 0 - } - ]), - tableView: tableView, - id: "row-\(index)", - hash: "\(viewItem.checked)", - autoDeselect: true, - dynamicHeight: { width in - CellBuilderNew.height( - containerWidth: width, - backgroundStyle: backgroundStyle, - text: text, - font: textFont, - verticalPadding: .margin16, - elements: [.fixed(width: .iconSize24), .multiline] - ) + rootElement: .hStack([ + .image24 { component in + component.imageView.image = UIImage(named: viewItem.checked ? "checkbox_active_24" : "checkbox_diactive_24") }, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + .text { component in + component.font = textFont + component.textColor = .themeLeah + component.text = text + component.numberOfLines = 0 }, - action: action + ]), + tableView: tableView, + id: "row-\(index)", + hash: "\(viewItem.checked)", + autoDeselect: true, + dynamicHeight: { width in + CellBuilderNew.height( + containerWidth: width, + backgroundStyle: backgroundStyle, + text: text, + font: textFont, + verticalPadding: .margin16, + elements: [.fixed(width: .iconSize24), .multiline] + ) + }, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + }, + action: action ) } func buildSections() -> [SectionProtocol] { [ Section( - id: "terms", - headerState: .margin(height: .margin12), - footerState: .margin(height: viewModel.buttonVisible ? .margin32 + .heightButton + .margin32 : .margin32), - rows: viewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, index: index, isFirst: index == 0, isLast: index == viewItems.count - 1) - } - ) + id: "terms", + headerState: .margin(height: .margin12), + footerState: .margin(height: viewModel.buttonVisible ? .margin32 + .heightButton + .margin32 : .margin32), + rows: viewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, index: index, isFirst: index == 0, isLast: index == viewItems.count - 1) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewModel.swift index b99a7dade3..4046740f35 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Terms/TermsViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class TermsViewModel { private let termCount = 5 @@ -15,14 +15,14 @@ class TermsViewModel { self.service = service if service.termsAccepted { - (0.. { viewItemsRelay.asDriver() } @@ -60,14 +58,11 @@ extension TermsViewModel { func onTapAgree() { service.setTermsAccepted() } - } extension TermsViewModel { - struct ViewItem { let text: String let checked: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkModule.swift index 473f075891..c32f57087e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkModule.swift @@ -1,12 +1,10 @@ import UIKit struct UnlinkModule { - static func viewController(account: Account) -> UIViewController { let service = UnlinkService(account: account, accountManager: App.shared.accountManager) let viewModel = UnlinkViewModel(service: service) let viewController = account.watchAccount ? UnlinkWatchViewController(viewModel: viewModel) : UnlinkViewController(viewModel: viewModel) return viewController.toBottomSheet } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkService.swift index 1cd2e24486..432edcd536 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkService.swift @@ -6,13 +6,10 @@ class UnlinkService { self.account = account self.accountManager = accountManager } - } extension UnlinkService { - func deleteAccount() { accountManager.delete(account: account) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewController.swift index 6bfec7c5e6..7bac2649e2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import SectionsTableView -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SectionsTableView +import ThemeKit +import UIKit class UnlinkViewController: ThemeActionSheetController { private let viewModel: UnlinkViewModel @@ -22,7 +22,8 @@ class UnlinkViewController: ThemeActionSheetController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -35,9 +36,9 @@ class UnlinkViewController: ThemeActionSheetController { } titleView.bind( - image: .trash, - title: "settings_manage_keys.delete.title".localized, - viewController: self + image: .trash, + title: "settings_manage_keys.delete.title".localized, + viewController: self ) view.addSubview(tableView) @@ -89,39 +90,37 @@ class UnlinkViewController: ThemeActionSheetController { } extension UnlinkViewController: SectionsDataSource { - private func checkboxRow(viewItem: UnlinkViewModel.ViewItem, index: Int, isFirst: Bool, isLast: Bool) -> RowProtocol { Row( - id: "checkbox_\(index)", - hash: "\(viewItem.checked)", - autoDeselect: true, - dynamicHeight: { width in - CheckboxCell.height(containerWidth: width, text: viewItem.text, backgroundStyle: .lawrence) - }, - bind: { cell, _ in - cell.bind( - text: viewItem.text, - checked: viewItem.checked, - backgroundStyle: .bordered, - isFirst: isFirst, - isLast: isLast - ) - }, - action: { [weak self] _ in - self?.viewModel.onTap(index: index) - } + id: "checkbox_\(index)", + hash: "\(viewItem.checked)", + autoDeselect: true, + dynamicHeight: { width in + CheckboxCell.height(containerWidth: width, text: viewItem.text, backgroundStyle: .lawrence) + }, + bind: { cell, _ in + cell.bind( + text: viewItem.text, + checked: viewItem.checked, + backgroundStyle: .bordered, + isFirst: isFirst, + isLast: isLast + ) + }, + action: { [weak self] _ in + self?.viewModel.onTap(index: index) + } ) } func buildSections() -> [SectionProtocol] { [ Section( - id: "main", - rows: viewItems.enumerated().map { index, viewItem in - checkboxRow(viewItem: viewItem, index: index, isFirst: index == 0, isLast: index == viewItems.count - 1) - } - ) + id: "main", + rows: viewItems.enumerated().map { index, viewItem in + checkboxRow(viewItem: viewItem, index: index, isFirst: index == 0, isLast: index == viewItems.count - 1) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewModel.swift index 1ce7e885e8..886eeac4f3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkViewModel.swift @@ -1,33 +1,31 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class UnlinkViewModel { private let service: UnlinkService private let viewItemsRelay: BehaviorRelay<[ViewItem]> private let deleteEnabledRelay = BehaviorRelay(value: false) - private let successRelay = PublishRelay<()>() + private let successRelay = PublishRelay() init(service: UnlinkService) { self.service = service viewItemsRelay = BehaviorRelay(value: [ ViewItem(text: "settings_manage_keys.delete.confirmation_remove".localized), - ViewItem(text: "settings_manage_keys.delete.confirmation_loose".localized) + ViewItem(text: "settings_manage_keys.delete.confirmation_loose".localized), ]) syncDeleteEnabled() } private func syncDeleteEnabled() { - deleteEnabledRelay.accept(viewItemsRelay.value.allSatisfy { $0.checked }) + deleteEnabledRelay.accept(viewItemsRelay.value.allSatisfy(\.checked)) } - } extension UnlinkViewModel { - var viewItemsDriver: Driver<[ViewItem]> { viewItemsRelay.asDriver() } @@ -36,7 +34,7 @@ extension UnlinkViewModel { deleteEnabledRelay.asDriver() } - var successSignal: Signal<()> { + var successSignal: Signal { successRelay.asSignal() } @@ -56,11 +54,9 @@ extension UnlinkViewModel { service.deleteAccount() successRelay.accept(()) } - } extension UnlinkViewModel { - struct ViewItem { let text: String var checked: Bool @@ -70,5 +66,4 @@ extension UnlinkViewModel { checked = false } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkWatchViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkWatchViewController.swift index fedcac11f1..d16908518a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkWatchViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Unlink/UnlinkWatchViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import ThemeKit +import UIKit class UnlinkWatchViewController: ThemeActionSheetController { private let viewModel: UnlinkViewModel @@ -14,7 +14,8 @@ class UnlinkWatchViewController: ThemeActionSheetController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -29,9 +30,9 @@ class UnlinkWatchViewController: ThemeActionSheetController { } titleView.bind( - image: .warning, - title: "settings_manage_keys.delete.title".localized, - viewController: self + image: .warning, + title: "settings_manage_keys.delete.title".localized, + viewController: self ) let descriptionView = HighlightedDescriptionView() @@ -66,5 +67,4 @@ class UnlinkWatchViewController: ThemeActionSheetController { @objc private func onTapDeleteButton() { viewModel.onTapDelete() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SubscriptionInfo/SubscriptionInfoViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SubscriptionInfo/SubscriptionInfoViewController.swift index 5d0113dad8..f7f6e18c65 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SubscriptionInfo/SubscriptionInfoViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SubscriptionInfo/SubscriptionInfoViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import SnapKit -import ThemeKit import ComponentKit import SectionsTableView +import SnapKit +import ThemeKit +import UIKit class SubscriptionInfoViewController: ThemeViewController { private let tableView = SectionsTableView(style: .grouped) @@ -63,27 +63,24 @@ class SubscriptionInfoViewController: ThemeViewController { presentingViewController?.present(viewController, animated: true) } } - } extension SubscriptionInfoViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "info", - footerState: .margin(height: .margin32), - rows: [ - MarkdownViewController.header1Row(id: "header", string: "subscription_info.title".localized), - MarkdownViewController.header3Row(id: "info1-title", string: "subscription_info.info1.title".localized), - MarkdownViewController.textRow(id: "info1-text", string: "subscription_info.info1.text".localized), - MarkdownViewController.header3Row(id: "info2-title", string: "subscription_info.info2.title".localized), - MarkdownViewController.textRow(id: "info2-text", string: "subscription_info.info2.text".localized), - MarkdownViewController.header3Row(id: "info3-title", string: "subscription_info.info3.title".localized), - MarkdownViewController.textRow(id: "info4-text", string: "subscription_info.info3.text".localized), - ] - ) + id: "info", + footerState: .margin(height: .margin32), + rows: [ + MarkdownViewController.header1Row(id: "header", string: "subscription_info.title".localized), + MarkdownViewController.header3Row(id: "info1-title", string: "subscription_info.info1.title".localized), + MarkdownViewController.textRow(id: "info1-text", string: "subscription_info.info1.text".localized), + MarkdownViewController.header3Row(id: "info2-title", string: "subscription_info.info2.title".localized), + MarkdownViewController.textRow(id: "info2-text", string: "subscription_info.info2.text".localized), + MarkdownViewController.header3Row(id: "info3-title", string: "subscription_info.info3.title".localized), + MarkdownViewController.textRow(id: "info4-text", string: "subscription_info.info3.text".localized), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchDataSource.swift index 9ac0131547..057409df72 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchDataSource.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit -import OneInchKit +import ComponentKit import HUD -import RxSwift +import OneInchKit import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import ThemeKit +import UIKit class OneInchDataSource { private static let levelColors: [UIColor] = [.themeRemus, .themeJacob, .themeLucian] @@ -32,11 +32,11 @@ class OneInchDataSource { private let proceedButton = PrimaryButton() private let proceed2Button = PrimaryButton() - var onOpen: ((_ viewController: UIViewController, _ viaPush: Bool) -> ())? = nil - var onOpenSelectProvider: (() -> ())? = nil - var onOpenSettings: (() -> ())? = nil - var onClose: (() -> ())? = nil - var onReload: (() -> ())? = nil + var onOpen: ((_ viewController: UIViewController, _ viaPush: Bool) -> Void)? + var onOpenSelectProvider: (() -> Void)? + var onOpenSettings: (() -> Void)? + var onClose: (() -> Void)? + var onReload: (() -> Void)? weak var tableView: UITableView? @@ -68,26 +68,27 @@ class OneInchDataSource { initCells() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func initCells() { revokeButton.set(style: .yellow) - revokeButton.addTarget(self, action: #selector((onTapRevokeButton)), for: .touchUpInside) + revokeButton.addTarget(self, action: #selector(onTapRevokeButton), for: .touchUpInside) buttonStackCell.add(view: revokeButton) - approve1Button.addTarget(self, action: #selector((onTapApproveButton)), for: .touchUpInside) + approve1Button.addTarget(self, action: #selector(onTapApproveButton), for: .touchUpInside) buttonStackCell.add(view: approve1Button) errorCell.set(backgroundStyle: .transparent, isFirst: true) proceedButton.set(style: .yellow) - proceedButton.addTarget(self, action: #selector((onTapProceedButton)), for: .touchUpInside) + proceedButton.addTarget(self, action: #selector(onTapProceedButton), for: .touchUpInside) buttonStackCell.add(view: proceedButton) proceed2Button.set(style: .yellow, accessoryType: .icon(image: UIImage(named: "numbers_2_24"))) - proceed2Button.addTarget(self, action: #selector((onTapProceedButton)), for: .touchUpInside) + proceed2Button.addTarget(self, action: #selector(onTapProceedButton), for: .touchUpInside) buttonStackCell.add(view: proceed2Button) subscribeToViewModel() @@ -112,7 +113,7 @@ class OneInchDataSource { subscribe(disposeBag, viewModel.amountTypeIndexDriver) { [weak self] in self?.settingsHeaderView.setSelector(index: $0) } subscribe(disposeBag, viewModel.isAmountTypeAvailableDriver) { [weak self] in self?.settingsHeaderView.setSelector(isEnabled: $0) } - subscribe(disposeBag, allowanceViewModel.allowanceDriver) { [weak self] in self?.handle(allowance: $0) } + subscribe(disposeBag, allowanceViewModel.allowanceDriver) { [weak self] in self?.handle(allowance: $0) } } func viewDidAppear() { @@ -124,7 +125,7 @@ class OneInchDataSource { CellBuilderNew.buildStatic(cell: availableBalanceCell, rootElement: .hStack([ .textElement(text: .subhead2("send.available_balance".localized), parameters: .highHugging), - .textElement(text: .subhead2(balance, color: .themeLeah), parameters: .rightAlignment) + .textElement(text: .subhead2(balance, color: .themeLeah), parameters: .rightAlignment), ])) onReload?() @@ -152,7 +153,7 @@ class OneInchDataSource { self?.showInfo(description: InfoDescription(title: "swap.allowance".localized, text: "swap.dex_info.content_allowance".localized)) } }, - .textElement(text: .subhead2(allowance, color: .themeLucian), parameters: .rightAlignment) + .textElement(text: .subhead2(allowance, color: .themeLucian), parameters: .rightAlignment), ])) onReload?() @@ -171,7 +172,7 @@ class OneInchDataSource { private func handle(error: String?) { self.error = error - if let error = error { + if let error { errorCell.isVisible = true errorCell.bind(caution: TitledCaution(title: "alert.error".localized, text: error, type: .error)) } else { @@ -204,11 +205,11 @@ class OneInchDataSource { switch actionState { case .hidden: button.isHidden = true - case .enabled(let title): + case let .enabled(title): button.isHidden = false button.isEnabled = true button.setTitle(title, for: .normal) - case .disabled(let title): + case let .disabled(title): button.isHidden = false button.isEnabled = false button.setTitle(title, for: .normal) @@ -277,41 +278,43 @@ class OneInchDataSource { let cellViewItems = [ InfoCellViewItem( - id: "buy-price", - cell: buyPriceCell, - isVisible: noAlerts && lastBuyPrice != nil), + id: "buy-price", + cell: buyPriceCell, + isVisible: noAlerts && lastBuyPrice != nil + ), InfoCellViewItem( - id: "allowance", - cell: allowanceCell, - isVisible: noAlerts && lastAllowance != nil), + id: "allowance", + cell: allowanceCell, + isVisible: noAlerts && lastAllowance != nil + ), InfoCellViewItem( - id: "available-balance", - cell: availableBalanceCell, - isVisible: noAlerts && lastAvailableBalance != nil && lastBuyPrice == nil && lastAllowance == nil), + id: "available-balance", + cell: availableBalanceCell, + isVisible: noAlerts && lastAvailableBalance != nil && lastBuyPrice == nil && lastAllowance == nil + ), InfoCellViewItem( - id: "price-impact", - cell: priceImpactCell, - isVisible: noAlerts && lastPriceImpact != nil && lastAllowance == nil), + id: "price-impact", + cell: priceImpactCell, + isVisible: noAlerts && lastPriceImpact != nil && lastAllowance == nil + ), ] let firstIndex = cellViewItems.firstIndex(where: { $0.isVisible }) ?? -1 let lastIndex = cellViewItems.lastIndex(where: { $0.isVisible }) ?? -1 - let rows = cellViewItems.enumerated().map { index, viewItem in viewItem.cell.set(backgroundStyle: .externalBorderOnly, isFirst: firstIndex == index, isLast: lastIndex == index) return StaticRow( - cell: viewItem.cell, - id: viewItem.id, - height: viewItem.isVisible ? .heightSingleLineCell : 0 + cell: viewItem.cell, + id: viewItem.id, + height: viewItem.isVisible ? .heightSingleLineCell : 0 ) } - return Section( - id: "info", - headerState: .margin(height: noAlerts ? .margin12 : 0), - rows: rows + id: "info", + headerState: .margin(height: noAlerts ? .margin12 : 0), + rows: rows ) } @@ -322,107 +325,98 @@ class OneInchDataSource { } extension OneInchDataSource: ISwapDataSource { - var state: SwapModule.DataSourceState { SwapModule.DataSourceState( - tokenFrom: viewModel.tradeService.tokenIn, - tokenTo: viewModel.tradeService.tokenOut, - amountFrom: viewModel.tradeService.amountIn, - amountTo: viewModel.tradeService.amountOut, - exactFrom: false) + tokenFrom: viewModel.tradeService.tokenIn, + tokenTo: viewModel.tradeService.tokenOut, + amountFrom: viewModel.tradeService.amountIn, + amountTo: viewModel.tradeService.amountOut, + exactFrom: false + ) } var buildSections: [SectionProtocol] { var sections = [SectionProtocol]() sections.append(Section( - id: "header", - headerState: .static(view: settingsHeaderView, height: TextDropDownAndSettingsHeaderView.height), - rows: [ - ] + id: "header", + headerState: .static(view: settingsHeaderView, height: TextDropDownAndSettingsHeaderView.height), + rows: [ + ] )) sections.append(Section( - id: "main", - headerState: .margin(height: .margin8), - rows: [ - StaticRow( - cell: inputCell, - id: "input-card", - height: SwapInputCell.cellHeight - ) - ] + id: "main", + headerState: .margin(height: .margin8), + rows: [ + StaticRow( + cell: inputCell, + id: "input-card", + height: SwapInputCell.cellHeight + ), + ] )) sections.append(infoSection) let hasAlert = warningCell.descriptionText != nil || error != nil sections.append(Section(id: "error", - headerState: .margin(height: hasAlert ? .margin12 : 0), - rows: [ - StaticRow( - cell: warningCell, - id: "warning", - dynamicHeight: { [weak self] width in - if self?.error != nil { - return 0 - } - return self?.warningCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: errorCell, - id: "error", - dynamicHeight: { [weak self] width in - self?.errorCell.cellHeight(containerWidth: width) ?? 0 - } - ) - ] - )) + headerState: .margin(height: hasAlert ? .margin12 : 0), + rows: [ + StaticRow( + cell: warningCell, + id: "warning", + dynamicHeight: { [weak self] width in + if self?.error != nil { + return 0 + } + return self?.warningCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: errorCell, + id: "error", + dynamicHeight: { [weak self] width in + self?.errorCell.cellHeight(containerWidth: width) ?? 0 + } + ), + ])) sections.append(Section( - id: "buttons", - headerState: .margin(height: .margin16), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: buttonStackCell, - id: "button", - height: .heightButton - ) - ] + id: "buttons", + headerState: .margin(height: .margin16), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: buttonStackCell, + id: "button", + height: .heightButton + ), + ] )) return sections } - } extension OneInchDataSource: IPresentDelegate { - func present(viewController: UIViewController) { onOpen?(viewController, false) } - } extension OneInchDataSource: ISwapApproveDelegate { - func didApprove() { viewModel.didApprove() } - } extension OneInchDataSource: IDynamicHeightCellDelegate { - func onChangeHeight() { onReload?() } - } extension OneInchDataSource { - struct InfoCellViewItem { let id: String let cell: BaseThemeCell @@ -433,5 +427,4 @@ extension OneInchDataSource { let title: String let text: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchModule.swift index d8c43f7776..1fcfea0f68 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchModule.swift @@ -1,5 +1,5 @@ -import OneInchKit import EvmKit +import OneInchKit class OneInchModule { private let tradeService: OneInchTradeService @@ -13,56 +13,55 @@ class OneInchModule { } guard let apiKey = AppConfig.oneInchApiKey, - let swapKit = try? OneInchKit.Kit.instance(evmKit: evmKit, apiKey: apiKey) else { + let swapKit = try? OneInchKit.Kit.instance(evmKit: evmKit, apiKey: apiKey) + else { return nil } let oneInchProvider = OneInchProvider(swapKit: swapKit) tradeService = OneInchTradeService( - oneInchProvider: oneInchProvider, - state: dataSourceState, - evmKit: evmKit + oneInchProvider: oneInchProvider, + state: dataSourceState, + evmKit: evmKit ) allowanceService = SwapAllowanceService( - spenderAddress: oneInchProvider.routerAddress, - adapterManager: App.shared.adapterManager, - evmKit: evmKit + spenderAddress: oneInchProvider.routerAddress, + adapterManager: App.shared.adapterManager, + evmKit: evmKit ) pendingAllowanceService = SwapPendingAllowanceService( - spenderAddress: oneInchProvider.routerAddress, - adapterManager: App.shared.adapterManager, - allowanceService: allowanceService + spenderAddress: oneInchProvider.routerAddress, + adapterManager: App.shared.adapterManager, + allowanceService: allowanceService ) service = OneInchService( - dex: dex, - evmKit: evmKit, - tradeService: tradeService, - allowanceService: allowanceService, - pendingAllowanceService: pendingAllowanceService, - adapterManager: App.shared.adapterManager + dex: dex, + evmKit: evmKit, + tradeService: tradeService, + allowanceService: allowanceService, + pendingAllowanceService: pendingAllowanceService, + adapterManager: App.shared.adapterManager ) } - } extension OneInchModule: ISwapProvider { - var dataSource: ISwapDataSource { let allowanceViewModel = SwapAllowanceViewModel(errorProvider: service, allowanceService: allowanceService, pendingAllowanceService: pendingAllowanceService) let viewModel = OneInchViewModel( - service: service, - tradeService: tradeService, - switchService: AmountTypeSwitchService(userDefaultsStorage: App.shared.userDefaultsStorage, useLocalStorage: false), - allowanceService: allowanceService, - pendingAllowanceService: pendingAllowanceService, - currencyManager: App.shared.currencyManager, - viewItemHelper: SwapViewItemHelper() + service: service, + tradeService: tradeService, + switchService: AmountTypeSwitchService(userDefaultsStorage: App.shared.userDefaultsStorage, useLocalStorage: false), + allowanceService: allowanceService, + pendingAllowanceService: pendingAllowanceService, + currencyManager: App.shared.currencyManager, + viewItemHelper: SwapViewItemHelper() ) return OneInchDataSource( - viewModel: viewModel, - allowanceViewModel: allowanceViewModel + viewModel: viewModel, + allowanceViewModel: allowanceViewModel ) } @@ -72,11 +71,11 @@ extension OneInchModule: ISwapProvider { var swapState: SwapModule.DataSourceState { SwapModule.DataSourceState( - tokenFrom: tradeService.tokenIn, - tokenTo: tradeService.tokenOut, - amountFrom: tradeService.amountIn, - amountTo: tradeService.amountOut, - exactFrom: true) + tokenFrom: tradeService.tokenIn, + tokenTo: tradeService.tokenOut, + amountFrom: tradeService.amountIn, + amountTo: tradeService.amountOut, + exactFrom: true + ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchProvider.swift index 60c7ec7c67..1aed582981 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchProvider.swift @@ -1,11 +1,10 @@ -import Foundation -import OneInchKit -import RxSwift +import BigInt import EvmKit import Foundation -import MarketKit -import BigInt import HsExtensions +import MarketKit +import OneInchKit +import RxSwift class OneInchProvider { private let swapKit: OneInchKit.Kit @@ -22,15 +21,13 @@ class OneInchProvider { private func address(token: MarketKit.Token) throws -> EvmKit.Address { switch token.type { case .native: return try EvmKit.Address(hex: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") - case .eip20(let address): return try EvmKit.Address(hex: address) + case let .eip20(address): return try EvmKit.Address(hex: address) default: throw SwapError.invalidAddress } } - } extension OneInchProvider { - var routerAddress: EvmKit.Address { swapKit.routerAddress } @@ -45,16 +42,16 @@ extension OneInchProvider { let addressTo = try address(token: tokenOut) return swapKit.quoteSingle( - fromToken: addressFrom, - toToken: addressTo, - amount: amountUnits, - protocols: nil, - gasPrice: nil, - complexityLevel: nil, - connectorTokens: nil, - gasLimit: nil, - mainRouteParts: nil, - parts: nil + fromToken: addressFrom, + toToken: addressTo, + amount: amountUnits, + protocols: nil, + gasPrice: nil, + complexityLevel: nil, + connectorTokens: nil, + gasLimit: nil, + mainRouteParts: nil, + parts: nil ) } catch { return Single.error(error) @@ -71,34 +68,30 @@ extension OneInchProvider { let addressTo = try address(token: tokenTo) return swapKit.swapSingle( - fromToken: addressFrom, - toToken: addressTo, - amount: amountUnits, - slippage: slippage, - protocols: nil, - recipient: recipient, - gasPrice: gasPrice, - burnChi: nil, - complexityLevel: nil, - connectorTokens: nil, - allowPartialFill: nil, - gasLimit: nil, - mainRouteParts: nil, - parts: nil + fromToken: addressFrom, + toToken: addressTo, + amount: amountUnits, + slippage: slippage, + protocols: nil, + recipient: recipient, + gasPrice: gasPrice, + burnChi: nil, + complexityLevel: nil, + connectorTokens: nil, + allowPartialFill: nil, + gasLimit: nil, + mainRouteParts: nil, + parts: nil ) } catch { return Single.error(error) } - } - } extension OneInchProvider { - enum SwapError: Error { case invalidAddress case insufficientAmount } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchService.swift index 0f1af9fa88..a19cc6d6a1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchService.swift @@ -1,11 +1,11 @@ -import RxSwift -import RxRelay -import HsToolKit -import UniswapKit import BigInt import EvmKit import Foundation +import HsToolKit import MarketKit +import RxRelay +import RxSwift +import UniswapKit class OneInchService { let dex: SwapModule.Dex @@ -28,7 +28,7 @@ class OneInchService { private let errorsRelay = PublishRelay<[Error]>() private(set) var errors: [Error] = [] { didSet { - if oldValue.isEmpty && errors.isEmpty { + if oldValue.isEmpty, errors.isEmpty { return } errorsRelay.accept(errors) @@ -51,7 +51,7 @@ class OneInchService { private let scheduler = SerialDispatchQueueScheduler(qos: .userInitiated, internalSerialQueueName: "\(AppConfig.label).swap_service") - init(dex: SwapModule.Dex, evmKit: EvmKit.Kit, tradeService: OneInchTradeService, allowanceService: SwapAllowanceService, pendingAllowanceService: SwapPendingAllowanceService, adapterManager: AdapterManager) { + init(dex: SwapModule.Dex, evmKit _: EvmKit.Kit, tradeService: OneInchTradeService, allowanceService: SwapAllowanceService, pendingAllowanceService: SwapPendingAllowanceService, adapterManager: AdapterManager) { self.dex = dex self.tradeService = tradeService self.allowanceService = allowanceService @@ -82,7 +82,7 @@ class OneInchService { } } - private func onUpdateTrade(state: OneInchTradeService.State) { + private func onUpdateTrade(state _: OneInchTradeService.State) { syncState() } @@ -92,7 +92,7 @@ class OneInchService { pendingAllowanceService.set(token: tokenIn) } - private func onUpdate(amountIn: Decimal?) { + private func onUpdate(amountIn _: Decimal?) { syncState() } @@ -105,9 +105,10 @@ class OneInchService { } private func checkAllowanceError(allowance: CoinValue) -> Error? { - guard let balanceIn = balanceIn, + guard let balanceIn, balanceIn >= tradeService.amountIn, - tradeService.amountIn > allowance.value else { + tradeService.amountIn > allowance.value + else { return nil } @@ -127,9 +128,9 @@ class OneInchService { switch tradeService.state { case .loading: loading = true - case .ready(let tradeParameters): + case let .ready(tradeParameters): parameters = tradeParameters - case .notReady(let errors): + case let .notReady(errors): allErrors.append(contentsOf: errors) } @@ -137,16 +138,16 @@ class OneInchService { switch allowanceState { case .loading: loading = true - case .ready(let allowance): + case let .ready(allowance): if let error = checkAllowanceError(allowance: allowance) { allErrors.append(error) } - case .notReady(let error): + case let .notReady(error): allErrors.append(error) } } - if let balanceIn = balanceIn { + if let balanceIn { if tradeService.amountIn > balanceIn { allErrors.append(SwapModule.SwapError.insufficientBalanceIn) } @@ -164,7 +165,7 @@ class OneInchService { if loading { state = .loading - } else if let parameters = parameters, allErrors.isEmpty { + } else if let parameters, allErrors.isEmpty { state = .ready(parameters: parameters) } else { state = .notReady @@ -174,11 +175,9 @@ class OneInchService { private func balance(token: MarketKit.Token) -> Decimal? { (adapterManager.adapter(for: token) as? IBalanceAdapter)?.balanceData.available } - } extension OneInchService: ISwapErrorProvider { - var stateObservable: Observable { stateRelay.asObservable() } @@ -195,19 +194,17 @@ extension OneInchService: ISwapErrorProvider { balanceOutRelay.asObservable() } - func approveData(amount: Decimal? = nil) -> SwapAllowanceService.ApproveData? { + func approveData(amount: Decimal? = nil) -> SwapAllowanceService.ApproveData? { let amount = amount ?? balanceIn - guard let amount = amount else { + guard let amount else { return nil } return allowanceService.approveData(dex: dex, amount: amount) } - } extension OneInchService { - enum State: Equatable { case loading case ready(parameters: OneInchSwapParameters) @@ -215,19 +212,18 @@ extension OneInchService { var parameters: OneInchSwapParameters? { switch self { - case .ready(let parameters): return parameters + case let .ready(parameters): return parameters default: return nil } } - static func ==(lhs: State, rhs: State) -> Bool { + static func == (lhs: State, rhs: State) -> Bool { switch (lhs, rhs) { case (.loading, .loading): return true - case (.ready(let lhsParams), .ready(let rhsParams)): return lhsParams == rhsParams + case let (.ready(lhsParams), .ready(rhsParams)): return lhsParams == rhsParams case (.notReady, .notReady): return true default: return false } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchTradeService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchTradeService.swift index e311778028..d4ec2ee12b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchTradeService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchTradeService.swift @@ -1,9 +1,9 @@ -import Foundation import EvmKit +import Foundation +import MarketKit import OneInchKit -import RxSwift import RxRelay -import MarketKit +import RxSwift class OneInchTradeService { private static let timerFramePerSecond = 30 @@ -81,11 +81,11 @@ class OneInchTradeService { amountIn = state.amountFrom ?? 0 evmKit.lastBlockHeightObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] blockNumber in - self?.syncQuote() - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] _ in + self?.syncQuote() + }) + .disposed(by: disposeBag) syncQuote() } @@ -95,21 +95,21 @@ class OneInchTradeService { let countdownValue = Int(syncInterval) * Self.timerFramePerSecond Observable - .interval(.milliseconds(1000 / Self.timerFramePerSecond), scheduler: ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .map { - countdownValue - $0 - } - .takeUntil(.inclusive, predicate: { $0 == 0 }) - .subscribe(onNext: { [weak self] value in - self?.countdownTimerRelay.accept(Float(value) / Float(countdownValue)) - }, onCompleted: { [weak self] in - self?.syncQuote() - }) - .disposed(by: refreshTimerDisposeBag) + .interval(.milliseconds(1000 / Self.timerFramePerSecond), scheduler: ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .map { + countdownValue - $0 + } + .takeUntil(.inclusive, predicate: { $0 == 0 }) + .subscribe(onNext: { [weak self] value in + self?.countdownTimerRelay.accept(Float(value) / Float(countdownValue)) + }, onCompleted: { [weak self] in + self?.syncQuote() + }) + .disposed(by: refreshTimerDisposeBag) } @discardableResult private func syncQuote() -> Bool { - guard let tokenIn = tokenIn, let tokenOut = tokenOut else { + guard let tokenIn, let tokenOut else { state = .notReady(errors: []) return false } @@ -127,22 +127,22 @@ class OneInchTradeService { } oneInchProvider.quoteSingle(tokenIn: tokenIn, tokenOut: tokenOut, amount: amountIn) - .subscribe(onSuccess: { [weak self] quote in - self?.handle(quote: quote, tokenFrom: tokenIn, tokenTo: tokenOut, amountFrom: amountIn) - }, onError: { [weak self] error in - var identifiedError = error.convertedError - - if let error = identifiedError as? AppError, - case .invalidResponse(let reason) = error { - - if reason.contains("liquidity") { - identifiedError = AppError.oneInch(reason: .insufficientLiquidity) - } + .subscribe(onSuccess: { [weak self] quote in + self?.handle(quote: quote, tokenFrom: tokenIn, tokenTo: tokenOut, amountFrom: amountIn) + }, onError: { [weak self] error in + var identifiedError = error.convertedError + + if let error = identifiedError as? AppError, + case let .invalidResponse(reason) = error + { + if reason.contains("liquidity") { + identifiedError = AppError.oneInch(reason: .insufficientLiquidity) } + } - self?.state = .notReady(errors: [identifiedError]) - }) - .disposed(by: quoteDisposeBag) + self?.state = .notReady(errors: [identifiedError]) + }) + .disposed(by: quoteDisposeBag) return true } @@ -163,11 +163,9 @@ class OneInchTradeService { state = .ready(parameters: parameters) } - } extension OneInchTradeService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -246,15 +244,12 @@ extension OneInchTradeService { set(tokenIn: swapToken) } - } extension OneInchTradeService { - enum State { case loading case ready(parameters: OneInchSwapParameters) case notReady(errors: [Error]) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchViewModel.swift index fbc1b0c001..db8ebc61d2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/OneInch/OneInchViewModel.swift @@ -1,8 +1,8 @@ +import EvmKit import Foundation -import RxSwift import RxCocoa +import RxSwift import UniswapKit -import EvmKit class OneInchViewModel { private let disposeBag = DisposeBag() @@ -65,7 +65,7 @@ class OneInchViewModel { private func handleObservable(errors: [Error]? = nil) { queue.async { [weak self] in - if let errors = errors { + if let errors { self?.sync(errors: errors) } @@ -93,14 +93,15 @@ class OneInchViewModel { switch state { case .loading: loading = true - case .ready(let parameters): + case let .ready(parameters): if !parameters.amountFrom.isZero, !parameters.amountTo.isZero { let executionPrice = parameters.amountTo / parameters.amountFrom let invertedPrice = 1 / executionPrice let prices = viewItemHelper.sortedPrices( - executionPrice: executionPrice, - invertedPrice: invertedPrice, - tokenIn: tradeService.tokenIn, tokenOut: tradeService.tokenOut) + executionPrice: executionPrice, + invertedPrice: invertedPrice, + tokenIn: tradeService.tokenIn, tokenOut: tradeService.tokenOut + ) buyPriceRelay.accept(SwapPriceCell.PriceViewItem(price: prices?.0, revertedPrice: prices?.1)) } else { buyPriceRelay.accept(nil) @@ -172,12 +173,12 @@ class OneInchViewModel { } else if case .notReady = tradeService.state { revokeWarning = nil approveStep = .notApproved - } else if service.errors.contains(where: { .insufficientBalanceIn == $0 as? SwapModule.SwapError }) { + } else if service.errors.contains(where: { $0 as? SwapModule.SwapError == .insufficientBalanceIn }) { approveStep = .notApproved } else if revokeWarning != nil { revokeAction = .enabled(title: "button.revoke".localized) approveStep = .revokeRequired - } else if service.errors.contains(where: { .insufficientAllowance == $0 as? SwapModule.SwapError }) { + } else if service.errors.contains(where: { $0 as? SwapModule.SwapError == .insufficientAllowance }) { approveAction = .enabled(title: "button.approve".localized) approveStep = .approveRequired } else if case .approved = pendingAllowanceService.state { @@ -204,11 +205,9 @@ class OneInchViewModel { private func sync(toggleAvailable: Bool) { isAmountToggleAvailableRelay.accept(toggleAvailable) } - } extension OneInchViewModel { - var amountTypeSelectorItems: [String] { ["swap.amount_type.coin".localized, currencyManager.baseCurrency.code] } @@ -285,7 +284,7 @@ extension OneInchViewModel { tradeService.switchCoins() } - func onChangeAmountType(index: Int) { + func onChangeAmountType(index _: Int) { switchService.toggle() } @@ -310,21 +309,18 @@ extension OneInchViewModel { } func onTapProceed() { - guard case .ready(let parameters) = service.state else { + guard case let .ready(parameters) = service.state else { return } openConfirmRelay.accept(parameters) } - } extension OneInchViewModel { - enum ActionState { case hidden case enabled(title: String) case disabled(title: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/SwapViewItemHelper.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/SwapViewItemHelper.swift index 4d1951fc50..47501ae613 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/SwapViewItemHelper.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/SwapViewItemHelper.swift @@ -1,11 +1,10 @@ import Foundation -import UniswapKit import MarketKit +import UniswapKit class SwapViewItemHelper { - func sortedPrices(executionPrice: Decimal?, invertedPrice: Decimal?, tokenIn: MarketKit.Token?, tokenOut: MarketKit.Token?) -> (String, String)? { - guard let price = executionPrice, let inverted = invertedPrice, let tokenOut = tokenOut, let tokenIn = tokenIn else { + guard let price = executionPrice, let inverted = invertedPrice, let tokenOut, let tokenIn else { return nil } @@ -21,13 +20,13 @@ class SwapViewItemHelper { } func priceImpactViewItem(priceImpact: Decimal?, impactLevel: UniswapTradeService.PriceImpactLevel?, minLevel: UniswapTradeService.PriceImpactLevel = .normal) -> UniswapModule.PriceImpactViewItem? { - guard var priceImpact = priceImpact, let impactLevel, impactLevel.rawValue >= minLevel.rawValue else { + guard var priceImpact, let impactLevel, impactLevel.rawValue >= minLevel.rawValue else { return nil } priceImpact.negate() return UniswapModule.PriceImpactViewItem( - value: priceImpact.description + "%", - level: impactLevel + value: priceImpact.description + "%", + level: impactLevel ) } @@ -39,11 +38,9 @@ class SwapViewItemHelper { let ttl = Decimal(floatLiteral: floor(deadline / 60)) return deadline == TradeOptions.defaultTtl ? nil : "swap.advanced_settings.deadline_minute".localized(ttl.description) } - } extension SwapViewItemHelper { - struct PriceCoinValue { let baseCoin: Coin let quoteCoinValue: CoinValue @@ -51,7 +48,5 @@ extension SwapViewItemHelper { var formattedFull: String { ValueFormatter.instance.formatFull(coinValue: quoteCoinValue).map { "1 " + [baseCoin.code, $0].joined(separator: " = ") } ?? "" } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapDataSource.swift index 70c8b2261b..7080dc2d3d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapDataSource.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit -import UniswapKit +import ComponentKit import HUD -import RxSwift import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import ThemeKit +import UIKit +import UniswapKit class UniswapDataSource { private static let levelColors: [UIColor] = [.themeRemus, .themeJacob, .themeLucian, .themeLucian] @@ -32,11 +32,11 @@ class UniswapDataSource { private let proceedButton = PrimaryButton() private let proceed2Button = PrimaryButton() - var onOpen: ((_ viewController: UIViewController, _ viaPush: Bool) -> ())? = nil - var onOpenSelectProvider: (() -> ())? = nil - var onOpenSettings: (() -> ())? = nil - var onClose: (() -> ())? = nil - var onReload: (() -> ())? = nil + var onOpen: ((_ viewController: UIViewController, _ viaPush: Bool) -> Void)? + var onOpenSelectProvider: (() -> Void)? + var onOpenSettings: (() -> Void)? + var onClose: (() -> Void)? + var onReload: (() -> Void)? weak var tableView: UITableView? @@ -65,34 +65,32 @@ class UniswapDataSource { settingsHeaderView.onTapSelector = { [weak self] in self?.onChangeAmountType(index: $0) } settingsHeaderView.setSelector(items: viewModel.amountTypeSelectorItems) - initCells() } - func viewDidLoad() { + func viewDidLoad() {} - } - - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func initCells() { revokeButton.set(style: .yellow) - revokeButton.addTarget(self, action: #selector((onTapRevokeButton)), for: .touchUpInside) + revokeButton.addTarget(self, action: #selector(onTapRevokeButton), for: .touchUpInside) buttonStackCell.add(view: revokeButton) - approve1Button.addTarget(self, action: #selector((onTapApproveButton)), for: .touchUpInside) + approve1Button.addTarget(self, action: #selector(onTapApproveButton), for: .touchUpInside) buttonStackCell.add(view: approve1Button) errorCell.set(backgroundStyle: .transparent, isFirst: true) proceedButton.set(style: .yellow) - proceedButton.addTarget(self, action: #selector((onTapProceedButton)), for: .touchUpInside) + proceedButton.addTarget(self, action: #selector(onTapProceedButton), for: .touchUpInside) buttonStackCell.add(view: proceedButton) proceed2Button.set(style: .yellow, accessoryType: .icon(image: UIImage(named: "numbers_2_24"))) - proceed2Button.addTarget(self, action: #selector((onTapProceedButton)), for: .touchUpInside) + proceed2Button.addTarget(self, action: #selector(onTapProceedButton), for: .touchUpInside) buttonStackCell.add(view: proceed2Button) subscribeToViewModel() @@ -119,7 +117,7 @@ class UniswapDataSource { subscribe(disposeBag, viewModel.amountTypeIndexDriver) { [weak self] in self?.settingsHeaderView.setSelector(index: $0) } subscribe(disposeBag, viewModel.isAmountTypeAvailableDriver) { [weak self] in self?.settingsHeaderView.setSelector(isEnabled: $0) } - subscribe(disposeBag, allowanceViewModel.allowanceDriver) { [weak self] in self?.handle(allowance: $0) } + subscribe(disposeBag, allowanceViewModel.allowanceDriver) { [weak self] in self?.handle(allowance: $0) } } func viewDidAppear() { @@ -131,7 +129,7 @@ class UniswapDataSource { CellBuilderNew.buildStatic(cell: availableBalanceCell, rootElement: .hStack([ .textElement(text: .subhead2("send.available_balance".localized), parameters: .highHugging), - .textElement(text: .subhead2(balance, color: .themeLeah), parameters: .rightAlignment) + .textElement(text: .subhead2(balance, color: .themeLeah), parameters: .rightAlignment), ])) onReload?() @@ -149,7 +147,7 @@ class UniswapDataSource { self?.showInfo(title: "swap.dex_info.header_price_impact".localized, text: "swap.dex_info.content_price_impact".localized) } }, - .textElement(text: .subhead2(priceImpact?.value, color: color), parameters: .rightAlignment) + .textElement(text: .subhead2(priceImpact?.value, color: color), parameters: .rightAlignment), ])) onReload?() @@ -177,7 +175,7 @@ class UniswapDataSource { self?.showInfo(title: "swap.dex_info.header_allowance".localized, text: "swap.dex_info.content_allowance".localized) } }, - .textElement(text: .subhead2(allowance, color: .themeLucian), parameters: .rightAlignment) + .textElement(text: .subhead2(allowance, color: .themeLucian), parameters: .rightAlignment), ])) onReload?() @@ -205,7 +203,7 @@ class UniswapDataSource { private func handle(error: String?) { self.error = error - if let error = error { + if let error { errorCell.isVisible = true errorCell.bind(caution: TitledCaution(title: "alert.error".localized, text: error, type: .error)) } else { @@ -228,11 +226,11 @@ class UniswapDataSource { switch actionState { case .hidden: button.isHidden = true - case .enabled(let title): + case let .enabled(title): button.isHidden = false button.isEnabled = true button.setTitle(title, for: .normal) - case .disabled(let title): + case let .disabled(title): button.isHidden = false button.isEnabled = false button.setTitle(title, for: .normal) @@ -296,14 +294,14 @@ class UniswapDataSource { viewModel.onChangeAmountType(index: index) } - private func build(staticCell: BaseThemeCell, id: String, title: String, showInfo: Bool = false, value: String?, valueColor: UIColor, progress: CGFloat? = nil) { + private func build(staticCell: BaseThemeCell, id _: String, title: String, showInfo: Bool = false, value: String?, valueColor: UIColor, progress _: CGFloat? = nil) { var cellElements: [CellBuilderNew.CellElement] = [ .text { component in component.font = .subhead2 component.textColor = .themeGray component.text = title component.setContentHuggingPriority(.defaultHigh, for: .horizontal) - } + }, ] if showInfo { @@ -311,7 +309,7 @@ class UniswapDataSource { .margin8, .image20 { component in component.imageView.image = UIImage(named: "circle_information_20")?.withTintColor(.themeGray) - } + }, ]) } @@ -332,41 +330,43 @@ class UniswapDataSource { let cellViewItems = [ InfoCellViewItem( - id: "buy-price", - cell: buyPriceCell, - isVisible: noAlerts && lastBuyPrice != nil), + id: "buy-price", + cell: buyPriceCell, + isVisible: noAlerts && lastBuyPrice != nil + ), InfoCellViewItem( - id: "allowance", - cell: allowanceCell, - isVisible: noAlerts && lastAllowance != nil), + id: "allowance", + cell: allowanceCell, + isVisible: noAlerts && lastAllowance != nil + ), InfoCellViewItem( - id: "available-balance", - cell: availableBalanceCell, - isVisible: noAlerts && lastAvailableBalance != nil && lastBuyPrice == nil && lastAllowance == nil), + id: "available-balance", + cell: availableBalanceCell, + isVisible: noAlerts && lastAvailableBalance != nil && lastBuyPrice == nil && lastAllowance == nil + ), InfoCellViewItem( - id: "price-impact", - cell: priceImpactCell, - isVisible: noAlerts && lastPriceImpact != nil), + id: "price-impact", + cell: priceImpactCell, + isVisible: noAlerts && lastPriceImpact != nil + ), ] let firstIndex = cellViewItems.firstIndex(where: { $0.isVisible }) ?? -1 let lastIndex = cellViewItems.lastIndex(where: { $0.isVisible }) ?? -1 - let rows = cellViewItems.enumerated().map { index, viewItem in viewItem.cell.set(backgroundStyle: .externalBorderOnly, isFirst: firstIndex == index, isLast: lastIndex == index) return StaticRow( - cell: viewItem.cell, - id: viewItem.id, - height: viewItem.isVisible ? .heightSingleLineCell : 0 + cell: viewItem.cell, + id: viewItem.id, + height: viewItem.isVisible ? .heightSingleLineCell : 0 ) } - return Section( - id: "info", - headerState: .margin(height: noAlerts ? .margin12 : 0), - rows: rows + id: "info", + headerState: .margin(height: noAlerts ? .margin12 : 0), + rows: rows ) } @@ -374,112 +374,102 @@ class UniswapDataSource { let viewController = BottomSheetModule.description(title: title, text: text) onOpen?(viewController, false) } - } extension UniswapDataSource: ISwapDataSource { - var state: SwapModule.DataSourceState { let exactIn = viewModel.tradeService.tradeType == .exactIn return SwapModule.DataSourceState( - tokenFrom: viewModel.tradeService.tokenIn, - tokenTo: viewModel.tradeService.tokenOut, - amountFrom: viewModel.tradeService.amountIn, - amountTo: viewModel.tradeService.amountOut, - exactFrom: exactIn) + tokenFrom: viewModel.tradeService.tokenIn, + tokenTo: viewModel.tradeService.tokenOut, + amountFrom: viewModel.tradeService.amountIn, + amountTo: viewModel.tradeService.amountOut, + exactFrom: exactIn + ) } var buildSections: [SectionProtocol] { var sections = [SectionProtocol]() sections.append(Section( - id: "header", - headerState: .static(view: settingsHeaderView, height: TextDropDownAndSettingsHeaderView.height), - rows: [ - ] + id: "header", + headerState: .static(view: settingsHeaderView, height: TextDropDownAndSettingsHeaderView.height), + rows: [ + ] )) sections.append(Section( - id: "main", - headerState: .margin(height: .margin8), - rows: [ - StaticRow( - cell: inputCell, - id: "input-card", - height: SwapInputCell.cellHeight - ) - ] + id: "main", + headerState: .margin(height: .margin8), + rows: [ + StaticRow( + cell: inputCell, + id: "input-card", + height: SwapInputCell.cellHeight + ), + ] )) sections.append(infoSection) let hasAlert = warningCell.descriptionText != nil || error != nil sections.append(Section(id: "error", - headerState: .margin(height: hasAlert ? .margin12 : 0), - rows: [ - StaticRow( - cell: warningCell, - id: "warning", - dynamicHeight: { [weak self] width in - if self?.error != nil { - return 0 - } - return self?.warningCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: errorCell, - id: "error", - dynamicHeight: { [weak self] width in - self?.errorCell.cellHeight(containerWidth: width) ?? 0 - } - ) - ] - )) + headerState: .margin(height: hasAlert ? .margin12 : 0), + rows: [ + StaticRow( + cell: warningCell, + id: "warning", + dynamicHeight: { [weak self] width in + if self?.error != nil { + return 0 + } + return self?.warningCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: errorCell, + id: "error", + dynamicHeight: { [weak self] width in + self?.errorCell.cellHeight(containerWidth: width) ?? 0 + } + ), + ])) sections.append(Section( - id: "buttons", - headerState: .margin(height: .margin16), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: buttonStackCell, - id: "button", - height: .heightButton - ) - ] + id: "buttons", + headerState: .margin(height: .margin16), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: buttonStackCell, + id: "button", + height: .heightButton + ), + ] )) return sections } - } extension UniswapDataSource: IPresentDelegate { - func present(viewController: UIViewController) { onOpen?(viewController, false) } - } extension UniswapDataSource: ISwapApproveDelegate { - func didApprove() { viewModel.didApprove() } - } extension UniswapDataSource: IDynamicHeightCellDelegate { - func onChangeHeight() { onReload?() } - } extension UniswapDataSource { - class InfoCellViewItem { let id: String let cell: BaseThemeCell @@ -491,5 +481,4 @@ extension UniswapDataSource { self.isVisible = isVisible } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapModule.swift index 42de73b46f..f077093283 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapModule.swift @@ -1,6 +1,6 @@ +import EvmKit import Foundation import UniswapKit -import EvmKit class UniswapModule { private let tradeService: UniswapTradeService @@ -20,48 +20,46 @@ class UniswapModule { let uniswapRepository = UniswapProvider(swapKit: swapKit) tradeService = UniswapTradeService( - uniswapProvider: uniswapRepository, - state: dataSourceState, - evmKit: evmKit + uniswapProvider: uniswapRepository, + state: dataSourceState, + evmKit: evmKit ) allowanceService = SwapAllowanceService( - spenderAddress: uniswapRepository.routerAddress, - adapterManager: App.shared.adapterManager, - evmKit: evmKit + spenderAddress: uniswapRepository.routerAddress, + adapterManager: App.shared.adapterManager, + evmKit: evmKit ) pendingAllowanceService = SwapPendingAllowanceService( - spenderAddress: uniswapRepository.routerAddress, - adapterManager: App.shared.adapterManager, - allowanceService: allowanceService + spenderAddress: uniswapRepository.routerAddress, + adapterManager: App.shared.adapterManager, + allowanceService: allowanceService ) service = UniswapService( - dex: dex, - tradeService: tradeService, - allowanceService: allowanceService, - pendingAllowanceService: pendingAllowanceService, - adapterManager: App.shared.adapterManager + dex: dex, + tradeService: tradeService, + allowanceService: allowanceService, + pendingAllowanceService: pendingAllowanceService, + adapterManager: App.shared.adapterManager ) } - } extension UniswapModule: ISwapProvider { - var dataSource: ISwapDataSource { let allowanceViewModel = SwapAllowanceViewModel(errorProvider: service, allowanceService: allowanceService, pendingAllowanceService: pendingAllowanceService) let viewModel = UniswapViewModel( - service: service, - tradeService: tradeService, - switchService: AmountTypeSwitchService(userDefaultsStorage: App.shared.userDefaultsStorage, useLocalStorage: false), - allowanceService: allowanceService, - pendingAllowanceService: pendingAllowanceService, - currencyManager: App.shared.currencyManager, - viewItemHelper: SwapViewItemHelper() + service: service, + tradeService: tradeService, + switchService: AmountTypeSwitchService(userDefaultsStorage: App.shared.userDefaultsStorage, useLocalStorage: false), + allowanceService: allowanceService, + pendingAllowanceService: pendingAllowanceService, + currencyManager: App.shared.currencyManager, + viewItemHelper: SwapViewItemHelper() ) return UniswapDataSource( - viewModel: viewModel, - allowanceViewModel: allowanceViewModel + viewModel: viewModel, + allowanceViewModel: allowanceViewModel ) } @@ -73,17 +71,16 @@ extension UniswapModule: ISwapProvider { let exactIn = tradeService.tradeType == .exactIn return SwapModule.DataSourceState( - tokenFrom: tradeService.tokenIn, - tokenTo: tradeService.tokenOut, - amountFrom: tradeService.amountIn, - amountTo: tradeService.amountOut, - exactFrom: exactIn) + tokenFrom: tradeService.tokenIn, + tokenTo: tradeService.tokenOut, + amountFrom: tradeService.amountIn, + amountTo: tradeService.amountOut, + exactFrom: exactIn + ) } - } extension UniswapModule { - struct PriceImpactViewItem { let value: String let level: UniswapTradeService.PriceImpactLevel @@ -106,26 +103,21 @@ extension UniswapModule { enum TradeError: Error { case wrapUnwrapNotAllowed } - } extension UniswapKit.Kit.TradeError: LocalizedError { - public var errorDescription: String? { switch self { case .tradeNotFound: return "swap.trade_error.not_found".localized default: return nil } } - } extension UniswapModule.TradeError: LocalizedError { - public var errorDescription: String? { switch self { case .wrapUnwrapNotAllowed: return "swap.trade_error.wrap_unwrap_not_allowed".localized } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapProvider.swift index 58c1785011..92850c34f4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapProvider.swift @@ -1,7 +1,7 @@ -import Foundation -import UniswapKit import EvmKit +import Foundation import MarketKit +import UniswapKit class UniswapProvider { private let swapKit: UniswapKit.Kit @@ -13,15 +13,13 @@ class UniswapProvider { private func uniswapToken(token: MarketKit.Token) throws -> UniswapKit.Token { switch token.type { case .native: return swapKit.etherToken - case let .eip20(address): return swapKit.token(contractAddress: try EvmKit.Address(hex: address), decimals: token.decimals) + case let .eip20(address): return try swapKit.token(contractAddress: EvmKit.Address(hex: address), decimals: token.decimals) default: throw TokenError.unsupportedToken } } - } extension UniswapProvider { - var routerAddress: EvmKit.Address { swapKit.routerAddress } @@ -49,13 +47,10 @@ extension UniswapProvider { func transactionData(tradeData: TradeData) throws -> TransactionData { try swapKit.transactionData(tradeData: tradeData) } - } extension UniswapProvider { - enum TokenError: Error { case unsupportedToken } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapService.swift index b0bedc8f65..776232b90a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapService.swift @@ -1,11 +1,11 @@ -import RxSwift -import RxRelay -import HsToolKit -import UniswapKit import BigInt import EvmKit import Foundation +import HsToolKit import MarketKit +import RxRelay +import RxSwift +import UniswapKit class UniswapService { let dex: SwapModule.Dex @@ -28,7 +28,7 @@ class UniswapService { private let errorsRelay = PublishRelay<[Error]>() private(set) var errors: [Error] = [] { didSet { - if oldValue.isEmpty && errors.isEmpty { + if oldValue.isEmpty, errors.isEmpty { return } errorsRelay.accept(errors) @@ -82,7 +82,7 @@ class UniswapService { } } - private func onUpdateTrade(state: UniswapTradeService.State) { + private func onUpdateTrade(state _: UniswapTradeService.State) { syncState() } @@ -92,7 +92,7 @@ class UniswapService { pendingAllowanceService.set(token: token) } - private func onUpdate(amountIn: Decimal?) { + private func onUpdate(amountIn _: Decimal?) { syncState() } @@ -105,9 +105,10 @@ class UniswapService { } private func checkAllowanceError(allowance: CoinValue) -> Error? { - guard let balanceIn = balanceIn, + guard let balanceIn, balanceIn >= tradeService.amountIn, - tradeService.amountIn > allowance.value else { + tradeService.amountIn > allowance.value + else { return nil } @@ -127,9 +128,9 @@ class UniswapService { switch tradeService.state { case .loading: loading = true - case .ready(let trade): + case let .ready(trade): transactionData = try? tradeService.transactionData(tradeData: trade.tradeData) - case .notReady(let errors): + case let .notReady(errors): allErrors.append(contentsOf: errors) } @@ -137,16 +138,16 @@ class UniswapService { switch allowanceState { case .loading: loading = true - case .ready(let allowance): + case let .ready(allowance): if let error = checkAllowanceError(allowance: allowance) { allErrors.append(error) } - case .notReady(let error): + case let .notReady(error): allErrors.append(error) } } - if let balanceIn = balanceIn { + if let balanceIn { if tradeService.amountIn > balanceIn { allErrors.append(SwapModule.SwapError.insufficientBalanceIn) } @@ -164,7 +165,7 @@ class UniswapService { if loading { state = .loading - } else if let transactionData = transactionData, allErrors.isEmpty { + } else if let transactionData, allErrors.isEmpty { state = .ready(transactionData: transactionData) } else { state = .notReady @@ -174,11 +175,9 @@ class UniswapService { private func balance(token: MarketKit.Token) -> Decimal? { (adapterManager.adapter(for: token) as? IBalanceAdapter)?.balanceData.available } - } extension UniswapService: ISwapErrorProvider { - var stateObservable: Observable { stateRelay.asObservable() } @@ -195,32 +194,29 @@ extension UniswapService: ISwapErrorProvider { balanceOutRelay.asObservable() } - func approveData(amount: Decimal? = nil) -> SwapAllowanceService.ApproveData? { + func approveData(amount: Decimal? = nil) -> SwapAllowanceService.ApproveData? { let amount = amount ?? balanceIn - guard let amount = amount else { + guard let amount else { return nil } return allowanceService.approveData(dex: dex, amount: amount) } - } extension UniswapService { - enum State: Equatable { case loading case ready(transactionData: TransactionData) case notReady - static func ==(lhs: State, rhs: State) -> Bool { + static func == (lhs: State, rhs: State) -> Bool { switch (lhs, rhs) { case (.loading, .loading): return true - case (.ready(let lhsTransactionData), .ready(let rhsTransactionData)): return lhsTransactionData == rhsTransactionData + case let (.ready(lhsTransactionData), .ready(rhsTransactionData)): return lhsTransactionData == rhsTransactionData case (.notReady, .notReady): return true default: return false } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapTradeService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapTradeService.swift index 0c1df050cc..7e0e25cf5c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapTradeService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/Uniswap/UniswapTradeService.swift @@ -1,10 +1,10 @@ -import Foundation import EvmKit -import UniswapKit -import RxSwift -import RxRelay -import MarketKit +import Foundation import HsExtensions +import MarketKit +import RxRelay +import RxSwift +import UniswapKit class UniswapTradeService: ISwapSettingProvider { private static let timerFramePerSecond = 30 @@ -99,11 +99,11 @@ class UniswapTradeService: ISwapSettingProvider { } evmKit.lastBlockHeightObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] blockNumber in - self?.syncSwapData() - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] _ in + self?.syncSwapData() + }) + .disposed(by: disposeBag) syncSwapData() } @@ -113,21 +113,21 @@ class UniswapTradeService: ISwapSettingProvider { let countdownValue = Int(syncInterval) * Self.timerFramePerSecond Observable - .interval(.milliseconds(1000 / Self.timerFramePerSecond), scheduler: ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .map { - countdownValue - $0 - } - .takeUntil(.inclusive, predicate: { $0 == 0 }) - .subscribe(onNext: { [weak self] value in - self?.countdownTimerRelay.accept(Float(value) / Float(countdownValue)) - }, onCompleted: { [weak self] in - self?.syncSwapData() - }) - .disposed(by: refreshTimerDisposeBag) + .interval(.milliseconds(1000 / Self.timerFramePerSecond), scheduler: ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .map { + countdownValue - $0 + } + .takeUntil(.inclusive, predicate: { $0 == 0 }) + .subscribe(onNext: { [weak self] value in + self?.countdownTimerRelay.accept(Float(value) / Float(countdownValue)) + }, onCompleted: { [weak self] in + self?.syncSwapData() + }) + .disposed(by: refreshTimerDisposeBag) } private func syncSwapData() { - guard let tokenIn = tokenIn, let tokenOut = tokenOut else { + guard let tokenIn, let tokenOut else { state = .notReady(errors: []) return } @@ -136,7 +136,7 @@ class UniswapTradeService: ISwapSettingProvider { syncTimer() // if swapData == nil { - state = .loading + state = .loading // } Task { [weak self, uniswapProvider] in @@ -151,7 +151,7 @@ class UniswapTradeService: ISwapSettingProvider { } @discardableResult private func syncTradeData() -> Bool { - guard let swapData = swapData else { + guard let swapData else { return false } @@ -172,11 +172,11 @@ class UniswapTradeService: ISwapSettingProvider { if case UniswapKit.Kit.TradeError.tradeNotFound = error { let wethAddressString = uniswapProvider.wethAddress.hex - if case .native = tokenIn?.type, case .eip20(let address) = tokenOut?.type, address == wethAddressString { + if case .native = tokenIn?.type, case let .eip20(address) = tokenOut?.type, address == wethAddressString { error = UniswapModule.TradeError.wrapUnwrapNotAllowed } - if case .native = tokenOut?.type, case .eip20(let address) = tokenIn?.type, address == wethAddressString { + if case .native = tokenOut?.type, case let .eip20(address) = tokenIn?.type, address == wethAddressString { error = UniswapModule.TradeError.wrapUnwrapNotAllowed } } @@ -199,11 +199,9 @@ class UniswapTradeService: ISwapSettingProvider { let trade = Trade(tradeData: tradeData) state = .ready(trade: trade) } - } extension UniswapTradeService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -316,11 +314,9 @@ extension UniswapTradeService { set(tokenIn: swapToken) } - } extension UniswapTradeService { - enum State { case loading case ready(trade: Trade) @@ -343,13 +339,12 @@ extension UniswapTradeService { impactLevel = tradeData.priceImpact.map { priceImpact in switch priceImpact { - case 0.. SettingsViewItem { SettingsViewItem(slippage: viewItemHelper.slippage(settings.allowedSlippage), - deadline: viewItemHelper.deadline(settings.ttl), - recipient: settings.recipient?.title) + deadline: viewItemHelper.deadline(settings.ttl), + recipient: settings.recipient?.title) } private func sync(amountType: AmountTypeSwitchService.AmountType) { @@ -228,11 +229,9 @@ class UniswapViewModel { private func sync(toggleAvailable: Bool) { isAmountToggleAvailableRelay.accept(toggleAvailable) } - } extension UniswapViewModel { - var amountTypeSelectorItems: [String] { ["swap.amount_type.coin".localized, currencyManager.baseCurrency.code] } @@ -317,7 +316,7 @@ extension UniswapViewModel { tradeService.switchCoins() } - func onChangeAmountType(index: Int) { + func onChangeAmountType(index _: Int) { switchService.toggle() } @@ -342,7 +341,7 @@ extension UniswapViewModel { } func onTapProceed() { - guard case .ready(let transactionData) = service.state else { + guard case let .ready(transactionData) = service.state else { return } @@ -351,41 +350,40 @@ extension UniswapViewModel { } let swapInfo = SendEvmData.SwapInfo( - estimatedOut: tradeService.amountOut, - estimatedIn: tradeService.amountIn, - slippage: viewItemHelper.slippage(tradeService.settings.allowedSlippage), - deadline: viewItemHelper.deadline(tradeService.settings.ttl), - recipientDomain: tradeService.settings.recipient?.domain, - price: viewItemHelper.sortedPrices( - executionPrice: trade.tradeData.executionPrice, - invertedPrice: trade.tradeData.executionPriceInverted, - tokenIn: tradeService.tokenIn, - tokenOut: tradeService.tokenOut)?.0, - priceImpact: viewItemHelper.priceImpactViewItem(priceImpact: trade.tradeData.priceImpact, impactLevel: trade.impactLevel) + estimatedOut: tradeService.amountOut, + estimatedIn: tradeService.amountIn, + slippage: viewItemHelper.slippage(tradeService.settings.allowedSlippage), + deadline: viewItemHelper.deadline(tradeService.settings.ttl), + recipientDomain: tradeService.settings.recipient?.domain, + price: viewItemHelper.sortedPrices( + executionPrice: trade.tradeData.executionPrice, + invertedPrice: trade.tradeData.executionPriceInverted, + tokenIn: tradeService.tokenIn, + tokenOut: tradeService.tokenOut + )?.0, + priceImpact: viewItemHelper.priceImpactViewItem(priceImpact: trade.tradeData.priceImpact, impactLevel: trade.impactLevel) ) var impactWarnings = [Warning]() var impactErrors = [Error]() switch trade.impactLevel { - case .warning: impactWarnings = [UniswapModule.UniswapWarning.highPriceImpact] - case .forbidden: impactErrors = [UniswapModule.UniswapError.forbiddenPriceImpact(provider: "Uniswap")] // we can use url from dex + case .warning: impactWarnings = [UniswapModule.UniswapWarning.highPriceImpact] + case .forbidden: impactErrors = [UniswapModule.UniswapError.forbiddenPriceImpact(provider: "Uniswap")] // we can use url from dex default: () } let sendEvmData = SendEvmData( - transactionData: transactionData, - additionalInfo: .uniswap(info: swapInfo), - warnings: impactWarnings, - errors: impactErrors + transactionData: transactionData, + additionalInfo: .uniswap(info: swapInfo), + warnings: impactWarnings, + errors: impactErrors ) openConfirmRelay.accept(sendEvmData) } - } extension UniswapViewModel { - struct TradeViewItem { let executionPrice: String? let executionPriceInverted: String? @@ -404,5 +402,4 @@ extension UniswapViewModel { case enabled(title: String) case disabled(title: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3DataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3DataSource.swift index 4ff70b2a61..98cf258451 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3DataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3DataSource.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit -import UniswapKit +import ComponentKit import HUD -import RxSwift import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import ThemeKit +import UIKit +import UniswapKit class UniswapV3DataSource { private static let levelColors: [UIColor] = [.themeRemus, .themeJacob, .themeLucian] @@ -32,11 +32,11 @@ class UniswapV3DataSource { private let proceedButton = PrimaryButton() private let proceed2Button = PrimaryButton() - var onOpen: ((_ viewController: UIViewController, _ viaPush: Bool) -> ())? = nil - var onOpenSelectProvider: (() -> ())? = nil - var onOpenSettings: (() -> ())? = nil - var onClose: (() -> ())? = nil - var onReload: (() -> ())? = nil + var onOpen: ((_ viewController: UIViewController, _ viaPush: Bool) -> Void)? + var onOpenSelectProvider: (() -> Void)? + var onOpenSettings: (() -> Void)? + var onClose: (() -> Void)? + var onReload: (() -> Void)? weak var tableView: UITableView? @@ -65,34 +65,32 @@ class UniswapV3DataSource { settingsHeaderView.onTapSelector = { [weak self] in self?.onChangeAmountType(index: $0) } settingsHeaderView.setSelector(items: viewModel.amountTypeSelectorItems) - initCells() } - func viewDidLoad() { + func viewDidLoad() {} - } - - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func initCells() { revokeButton.set(style: .yellow) - revokeButton.addTarget(self, action: #selector((onTapRevokeButton)), for: .touchUpInside) + revokeButton.addTarget(self, action: #selector(onTapRevokeButton), for: .touchUpInside) buttonStackCell.add(view: revokeButton) - approve1Button.addTarget(self, action: #selector((onTapApproveButton)), for: .touchUpInside) + approve1Button.addTarget(self, action: #selector(onTapApproveButton), for: .touchUpInside) buttonStackCell.add(view: approve1Button) errorCell.set(backgroundStyle: .transparent, isFirst: true) proceedButton.set(style: .yellow) - proceedButton.addTarget(self, action: #selector((onTapProceedButton)), for: .touchUpInside) + proceedButton.addTarget(self, action: #selector(onTapProceedButton), for: .touchUpInside) buttonStackCell.add(view: proceedButton) proceed2Button.set(style: .yellow, accessoryType: .icon(image: UIImage(named: "numbers_2_24"))) - proceed2Button.addTarget(self, action: #selector((onTapProceedButton)), for: .touchUpInside) + proceed2Button.addTarget(self, action: #selector(onTapProceedButton), for: .touchUpInside) buttonStackCell.add(view: proceed2Button) subscribeToViewModel() @@ -119,7 +117,7 @@ class UniswapV3DataSource { subscribe(disposeBag, viewModel.amountTypeIndexDriver) { [weak self] in self?.settingsHeaderView.setSelector(index: $0) } subscribe(disposeBag, viewModel.isAmountTypeAvailableDriver) { [weak self] in self?.settingsHeaderView.setSelector(isEnabled: $0) } - subscribe(disposeBag, allowanceViewModel.allowanceDriver) { [weak self] in self?.handle(allowance: $0) } + subscribe(disposeBag, allowanceViewModel.allowanceDriver) { [weak self] in self?.handle(allowance: $0) } } func viewDidAppear() { @@ -131,7 +129,7 @@ class UniswapV3DataSource { CellBuilderNew.buildStatic(cell: availableBalanceCell, rootElement: .hStack([ .textElement(text: .subhead2("send.available_balance".localized), parameters: .highHugging), - .textElement(text: .subhead2(balance, color: .themeLeah), parameters: .rightAlignment) + .textElement(text: .subhead2(balance, color: .themeLeah), parameters: .rightAlignment), ])) onReload?() @@ -149,7 +147,7 @@ class UniswapV3DataSource { self?.showInfo(title: "swap.dex_info.header_price_impact".localized, text: "swap.dex_info.content_price_impact".localized) } }, - .textElement(text: .subhead2(priceImpact?.value, color: color), parameters: .rightAlignment) + .textElement(text: .subhead2(priceImpact?.value, color: color), parameters: .rightAlignment), ])) onReload?() @@ -177,7 +175,7 @@ class UniswapV3DataSource { self?.showInfo(title: "swap.dex_info.header_allowance".localized, text: "swap.dex_info.content_allowance".localized) } }, - .textElement(text: .subhead2(allowance, color: .themeLucian), parameters: .rightAlignment) + .textElement(text: .subhead2(allowance, color: .themeLucian), parameters: .rightAlignment), ])) onReload?() @@ -205,7 +203,7 @@ class UniswapV3DataSource { private func handle(error: String?) { self.error = error - if let error = error { + if let error { errorCell.isVisible = true errorCell.bind(caution: TitledCaution(title: "alert.error".localized, text: error, type: .error)) } else { @@ -228,11 +226,11 @@ class UniswapV3DataSource { switch actionState { case .hidden: button.isHidden = true - case .enabled(let title): + case let .enabled(title): button.isHidden = false button.isEnabled = true button.setTitle(title, for: .normal) - case .disabled(let title): + case let .disabled(title): button.isHidden = false button.isEnabled = false button.setTitle(title, for: .normal) @@ -296,14 +294,14 @@ class UniswapV3DataSource { viewModel.onChangeAmountType(index: index) } - private func build(staticCell: BaseThemeCell, id: String, title: String, showInfo: Bool = false, value: String?, valueColor: UIColor, progress: CGFloat? = nil) { + private func build(staticCell: BaseThemeCell, id _: String, title: String, showInfo: Bool = false, value: String?, valueColor: UIColor, progress _: CGFloat? = nil) { var cellElements: [CellBuilderNew.CellElement] = [ .text { component in component.font = .subhead2 component.textColor = .themeGray component.text = title component.setContentHuggingPriority(.defaultHigh, for: .horizontal) - } + }, ] if showInfo { @@ -311,7 +309,7 @@ class UniswapV3DataSource { .margin8, .image20 { component in component.imageView.image = UIImage(named: "circle_information_20")?.withTintColor(.themeGray) - } + }, ]) } @@ -332,41 +330,43 @@ class UniswapV3DataSource { let cellViewItems = [ InfoCellViewItem( - id: "buy-price", - cell: buyPriceCell, - isVisible: noAlerts && lastBuyPrice != nil), + id: "buy-price", + cell: buyPriceCell, + isVisible: noAlerts && lastBuyPrice != nil + ), InfoCellViewItem( - id: "allowance", - cell: allowanceCell, - isVisible: noAlerts && lastAllowance != nil), + id: "allowance", + cell: allowanceCell, + isVisible: noAlerts && lastAllowance != nil + ), InfoCellViewItem( - id: "available-balance", - cell: availableBalanceCell, - isVisible: noAlerts && lastAvailableBalance != nil && lastBuyPrice == nil && lastAllowance == nil), + id: "available-balance", + cell: availableBalanceCell, + isVisible: noAlerts && lastAvailableBalance != nil && lastBuyPrice == nil && lastAllowance == nil + ), InfoCellViewItem( - id: "price-impact", - cell: priceImpactCell, - isVisible: noAlerts && lastPriceImpact != nil), + id: "price-impact", + cell: priceImpactCell, + isVisible: noAlerts && lastPriceImpact != nil + ), ] let firstIndex = cellViewItems.firstIndex(where: { $0.isVisible }) ?? -1 let lastIndex = cellViewItems.lastIndex(where: { $0.isVisible }) ?? -1 - let rows = cellViewItems.enumerated().map { index, viewItem in viewItem.cell.set(backgroundStyle: .externalBorderOnly, isFirst: firstIndex == index, isLast: lastIndex == index) return StaticRow( - cell: viewItem.cell, - id: viewItem.id, - height: viewItem.isVisible ? .heightSingleLineCell : 0 + cell: viewItem.cell, + id: viewItem.id, + height: viewItem.isVisible ? .heightSingleLineCell : 0 ) } - return Section( - id: "info", - headerState: .margin(height: noAlerts ? .margin12 : 0), - rows: rows + id: "info", + headerState: .margin(height: noAlerts ? .margin12 : 0), + rows: rows ) } @@ -374,112 +374,102 @@ class UniswapV3DataSource { let viewController = BottomSheetModule.description(title: title, text: text) onOpen?(viewController, false) } - } extension UniswapV3DataSource: ISwapDataSource { - var state: SwapModule.DataSourceState { let exactIn = viewModel.tradeService.tradeType == .exactIn return SwapModule.DataSourceState( - tokenFrom: viewModel.tradeService.tokenIn, - tokenTo: viewModel.tradeService.tokenOut, - amountFrom: viewModel.tradeService.amountIn, - amountTo: viewModel.tradeService.amountOut, - exactFrom: exactIn) + tokenFrom: viewModel.tradeService.tokenIn, + tokenTo: viewModel.tradeService.tokenOut, + amountFrom: viewModel.tradeService.amountIn, + amountTo: viewModel.tradeService.amountOut, + exactFrom: exactIn + ) } var buildSections: [SectionProtocol] { var sections = [SectionProtocol]() sections.append(Section( - id: "header", - headerState: .static(view: settingsHeaderView, height: TextDropDownAndSettingsHeaderView.height), - rows: [ - ] + id: "header", + headerState: .static(view: settingsHeaderView, height: TextDropDownAndSettingsHeaderView.height), + rows: [ + ] )) sections.append(Section( - id: "main", - headerState: .margin(height: .margin8), - rows: [ - StaticRow( - cell: inputCell, - id: "input-card", - height: SwapInputCell.cellHeight - ) - ] + id: "main", + headerState: .margin(height: .margin8), + rows: [ + StaticRow( + cell: inputCell, + id: "input-card", + height: SwapInputCell.cellHeight + ), + ] )) sections.append(infoSection) let hasAlert = warningCell.descriptionText != nil || error != nil sections.append(Section(id: "error", - headerState: .margin(height: hasAlert ? .margin12 : 0), - rows: [ - StaticRow( - cell: warningCell, - id: "warning", - dynamicHeight: { [weak self] width in - if self?.error != nil { - return 0 - } - return self?.warningCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: errorCell, - id: "error", - dynamicHeight: { [weak self] width in - self?.errorCell.cellHeight(containerWidth: width) ?? 0 - } - ) - ] - )) + headerState: .margin(height: hasAlert ? .margin12 : 0), + rows: [ + StaticRow( + cell: warningCell, + id: "warning", + dynamicHeight: { [weak self] width in + if self?.error != nil { + return 0 + } + return self?.warningCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: errorCell, + id: "error", + dynamicHeight: { [weak self] width in + self?.errorCell.cellHeight(containerWidth: width) ?? 0 + } + ), + ])) sections.append(Section( - id: "buttons", - headerState: .margin(height: .margin16), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: buttonStackCell, - id: "button", - height: .heightButton - ) - ] + id: "buttons", + headerState: .margin(height: .margin16), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: buttonStackCell, + id: "button", + height: .heightButton + ), + ] )) return sections } - } extension UniswapV3DataSource: IPresentDelegate { - func present(viewController: UIViewController) { onOpen?(viewController, false) } - } extension UniswapV3DataSource: ISwapApproveDelegate { - func didApprove() { viewModel.didApprove() } - } extension UniswapV3DataSource: IDynamicHeightCellDelegate { - func onChangeHeight() { onReload?() } - } extension UniswapV3DataSource { - class InfoCellViewItem { let id: String let cell: BaseThemeCell @@ -491,5 +481,4 @@ extension UniswapV3DataSource { self.isVisible = isVisible } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Module.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Module.swift index b45689dcb5..b5821b977b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Module.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Module.swift @@ -1,6 +1,6 @@ +import EvmKit import Foundation import UniswapKit -import EvmKit class UniswapV3Module { private let tradeService: UniswapV3TradeService @@ -20,48 +20,46 @@ class UniswapV3Module { let uniswapRepository = UniswapV3Provider(swapKit: swapKit) tradeService = UniswapV3TradeService( - uniswapProvider: uniswapRepository, - state: dataSourceState, - evmKit: evmKit + uniswapProvider: uniswapRepository, + state: dataSourceState, + evmKit: evmKit ) allowanceService = SwapAllowanceService( - spenderAddress: uniswapRepository.routerAddress, - adapterManager: App.shared.adapterManager, - evmKit: evmKit + spenderAddress: uniswapRepository.routerAddress, + adapterManager: App.shared.adapterManager, + evmKit: evmKit ) pendingAllowanceService = SwapPendingAllowanceService( - spenderAddress: uniswapRepository.routerAddress, - adapterManager: App.shared.adapterManager, - allowanceService: allowanceService + spenderAddress: uniswapRepository.routerAddress, + adapterManager: App.shared.adapterManager, + allowanceService: allowanceService ) service = UniswapV3Service( - dex: dex, - tradeService: tradeService, - allowanceService: allowanceService, - pendingAllowanceService: pendingAllowanceService, - adapterManager: App.shared.adapterManager + dex: dex, + tradeService: tradeService, + allowanceService: allowanceService, + pendingAllowanceService: pendingAllowanceService, + adapterManager: App.shared.adapterManager ) } - } extension UniswapV3Module: ISwapProvider { - var dataSource: ISwapDataSource { let allowanceViewModel = SwapAllowanceViewModel(errorProvider: service, allowanceService: allowanceService, pendingAllowanceService: pendingAllowanceService) let viewModel = UniswapV3ViewModel( - service: service, - tradeService: tradeService, - switchService: AmountTypeSwitchService(userDefaultsStorage: App.shared.userDefaultsStorage, useLocalStorage: false), - allowanceService: allowanceService, - pendingAllowanceService: pendingAllowanceService, - currencyManager: App.shared.currencyManager, - viewItemHelper: SwapViewItemHelper() + service: service, + tradeService: tradeService, + switchService: AmountTypeSwitchService(userDefaultsStorage: App.shared.userDefaultsStorage, useLocalStorage: false), + allowanceService: allowanceService, + pendingAllowanceService: pendingAllowanceService, + currencyManager: App.shared.currencyManager, + viewItemHelper: SwapViewItemHelper() ) return UniswapV3DataSource( - viewModel: viewModel, - allowanceViewModel: allowanceViewModel + viewModel: viewModel, + allowanceViewModel: allowanceViewModel ) } @@ -73,17 +71,16 @@ extension UniswapV3Module: ISwapProvider { let exactIn = tradeService.tradeType == .exactIn return SwapModule.DataSourceState( - tokenFrom: tradeService.tokenIn, - tokenTo: tradeService.tokenOut, - amountFrom: tradeService.amountIn, - amountTo: tradeService.amountOut, - exactFrom: exactIn) + tokenFrom: tradeService.tokenIn, + tokenTo: tradeService.tokenOut, + amountFrom: tradeService.amountIn, + amountTo: tradeService.amountOut, + exactFrom: exactIn + ) } - } extension UniswapV3Module { - struct PriceImpactViewItem { let value: String let level: UniswapTradeService.PriceImpactLevel @@ -101,5 +98,4 @@ extension UniswapV3Module { enum TradeError: Error { case wrapUnwrapNotAllowed } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Provider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Provider.swift index 0db635566d..b1b1efc33e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Provider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Provider.swift @@ -1,7 +1,7 @@ -import Foundation -import UniswapKit import EvmKit +import Foundation import MarketKit +import UniswapKit class UniswapV3Provider { private let swapKit: UniswapKit.KitV3 @@ -13,15 +13,13 @@ class UniswapV3Provider { private func uniswapToken(token: MarketKit.Token) throws -> UniswapKit.Token { switch token.type { case .native: return swapKit.etherToken - case let .eip20(address): return swapKit.token(contractAddress: try EvmKit.Address(hex: address), decimals: token.decimals) + case let .eip20(address): return try swapKit.token(contractAddress: EvmKit.Address(hex: address), decimals: token.decimals) default: throw TokenError.unsupportedToken } } - } extension UniswapV3Provider { - var routerAddress: EvmKit.Address { swapKit.routerAddress } @@ -45,13 +43,10 @@ extension UniswapV3Provider { func transactionData(tradeData: TradeDataV3, tradeOptions: TradeOptions) throws -> TransactionData { try swapKit.transactionData(bestTrade: tradeData, tradeOptions: tradeOptions) } - } extension UniswapV3Provider { - enum TokenError: Error { case unsupportedToken } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Service.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Service.swift index 7e8c632db1..524e38da23 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Service.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3Service.swift @@ -1,11 +1,11 @@ -import RxSwift -import RxRelay -import HsToolKit -import UniswapKit import BigInt import EvmKit import Foundation +import HsToolKit import MarketKit +import RxRelay +import RxSwift +import UniswapKit class UniswapV3Service { let dex: SwapModule.Dex @@ -28,7 +28,7 @@ class UniswapV3Service { private let errorsRelay = PublishRelay<[Error]>() private(set) var errors: [Error] = [] { didSet { - if oldValue.isEmpty && errors.isEmpty { + if oldValue.isEmpty, errors.isEmpty { return } errorsRelay.accept(errors) @@ -82,7 +82,7 @@ class UniswapV3Service { } } - private func onUpdateTrade(state: UniswapV3TradeService.State) { + private func onUpdateTrade(state _: UniswapV3TradeService.State) { syncState() } @@ -92,7 +92,7 @@ class UniswapV3Service { pendingAllowanceService.set(token: token) } - private func onUpdate(amountIn: Decimal?) { + private func onUpdate(amountIn _: Decimal?) { syncState() } @@ -105,9 +105,10 @@ class UniswapV3Service { } private func checkAllowanceError(allowance: CoinValue) -> Error? { - guard let balanceIn = balanceIn, + guard let balanceIn, balanceIn >= tradeService.amountIn, - tradeService.amountIn > allowance.value else { + tradeService.amountIn > allowance.value + else { return nil } @@ -127,9 +128,9 @@ class UniswapV3Service { switch tradeService.state { case .loading: loading = true - case .ready(let trade): + case let .ready(trade): transactionData = try? tradeService.transactionData(tradeData: trade.tradeData) - case .notReady(let errors): + case let .notReady(errors): allErrors.append(contentsOf: errors) } @@ -137,16 +138,16 @@ class UniswapV3Service { switch allowanceState { case .loading: loading = true - case .ready(let allowance): + case let .ready(allowance): if let error = checkAllowanceError(allowance: allowance) { allErrors.append(error) } - case .notReady(let error): + case let .notReady(error): allErrors.append(error) } } - if let balanceIn = balanceIn { + if let balanceIn { if tradeService.amountIn > balanceIn { allErrors.append(SwapModule.SwapError.insufficientBalanceIn) } @@ -164,7 +165,7 @@ class UniswapV3Service { if loading { state = .loading - } else if let transactionData = transactionData, allErrors.isEmpty { + } else if let transactionData, allErrors.isEmpty { state = .ready(transactionData: transactionData) } else { state = .notReady @@ -174,11 +175,9 @@ class UniswapV3Service { private func balance(token: MarketKit.Token) -> Decimal? { (adapterManager.adapter(for: token) as? IBalanceAdapter)?.balanceData.available } - } extension UniswapV3Service: ISwapErrorProvider { - var stateObservable: Observable { stateRelay.asObservable() } @@ -195,32 +194,29 @@ extension UniswapV3Service: ISwapErrorProvider { balanceOutRelay.asObservable() } - func approveData(amount: Decimal? = nil) -> SwapAllowanceService.ApproveData? { + func approveData(amount: Decimal? = nil) -> SwapAllowanceService.ApproveData? { let amount = amount ?? balanceIn - guard let amount = amount else { + guard let amount else { return nil } return allowanceService.approveData(dex: dex, amount: amount) } - } extension UniswapV3Service { - enum State: Equatable { case loading case ready(transactionData: TransactionData) case notReady - static func ==(lhs: State, rhs: State) -> Bool { + static func == (lhs: State, rhs: State) -> Bool { switch (lhs, rhs) { case (.loading, .loading): return true - case (.ready(let lhsTransactionData), .ready(let rhsTransactionData)): return lhsTransactionData == rhsTransactionData + case let (.ready(lhsTransactionData), .ready(rhsTransactionData)): return lhsTransactionData == rhsTransactionData case (.notReady, .notReady): return true default: return false } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3TradeService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3TradeService.swift index 93eac59812..23da8c5f60 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3TradeService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3TradeService.swift @@ -1,11 +1,11 @@ import Combine -import Foundation import EvmKit -import UniswapKit -import RxSwift -import RxRelay -import MarketKit +import Foundation import HsExtensions +import MarketKit +import RxRelay +import RxSwift +import UniswapKit class UniswapV3TradeService: ISwapSettingProvider { private static let timerFramePerSecond: Int = 30 @@ -105,10 +105,10 @@ class UniswapV3TradeService: ISwapSettingProvider { } evmKit.lastBlockHeightPublisher - .sink { [weak self] blockNumber in - self?.syncTradeData() - } - .store(in: &cancellables) + .sink { [weak self] _ in + self?.syncTradeData() + } + .store(in: &cancellables) syncTradeData() } @@ -118,7 +118,7 @@ class UniswapV3TradeService: ISwapSettingProvider { let tickerCount = Int(syncInterval) * Self.timerFramePerSecond refreshTimerTask = Task { [weak self] in - for i in 0...tickerCount { + for i in 0 ... tickerCount { try await Task.sleep(nanoseconds: 1_000_000_000 / UInt64(Self.timerFramePerSecond)) self?.countdownTimerRelay.accept(Float(i) / Float(tickerCount)) } @@ -128,8 +128,9 @@ class UniswapV3TradeService: ISwapSettingProvider { } @discardableResult private func syncTradeData() -> Bool { - guard let tokenIn = tokenIn, - let tokenOut = tokenOut else { + guard let tokenIn, + let tokenOut + else { state = .notReady(errors: []) return false } @@ -156,11 +157,11 @@ class UniswapV3TradeService: ISwapSettingProvider { if case UniswapKit.KitV3.TradeError.tradeNotFound = error { let wethAddressString = uniswapProvider.wethAddress.hex - if case .native = tokenIn.type, case .eip20(let address) = tokenOut.type, address == wethAddressString { + if case .native = tokenIn.type, case let .eip20(address) = tokenOut.type, address == wethAddressString { convertedError = UniswapModule.TradeError.wrapUnwrapNotAllowed } - if case .native = tokenOut.type, case .eip20(let address) = tokenIn.type, address == wethAddressString { + if case .native = tokenOut.type, case let .eip20(address) = tokenIn.type, address == wethAddressString { convertedError = UniswapModule.TradeError.wrapUnwrapNotAllowed } } @@ -185,16 +186,13 @@ class UniswapV3TradeService: ISwapSettingProvider { let trade = Trade(tradeData: tradeData) state = .ready(trade: trade) } - } protocol IUniswapTradeService { var stateObservable: Observable { get } - } extension UniswapV3TradeService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -307,11 +305,9 @@ extension UniswapV3TradeService { set(tokenIn: swapToken) } - } extension UniswapV3TradeService { - enum State { case loading case ready(trade: Trade) @@ -339,5 +335,4 @@ extension UniswapV3TradeService { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3ViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3ViewModel.swift index 320d5ebd51..1d379fd3d9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3ViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Adapters/UniswapV3/UniswapV3ViewModel.swift @@ -1,9 +1,9 @@ +import EvmKit import Foundation -import RxSwift +import HsToolKit import RxCocoa +import RxSwift import UniswapKit -import EvmKit -import HsToolKit class UniswapV3ViewModel { private let disposeBag = DisposeBag() @@ -80,7 +80,7 @@ class UniswapV3ViewModel { } private func handleObservable(errors: [Error]? = nil) { - if let errors = errors { + if let errors { sync(errors: errors) } @@ -125,12 +125,13 @@ class UniswapV3ViewModel { switch tradeState { case .loading: loading = true - case .ready(let trade): + case let .ready(trade): if let executionPrice = trade.tradeData.executionPrice, !executionPrice.isZero { let prices = viewItemHelper.sortedPrices( - executionPrice: executionPrice, - invertedPrice: trade.tradeData.executionPriceInverted ?? (1 / executionPrice), - tokenIn: tradeService.tokenIn, tokenOut: tradeService.tokenOut) + executionPrice: executionPrice, + invertedPrice: trade.tradeData.executionPriceInverted ?? (1 / executionPrice), + tokenIn: tradeService.tokenIn, tokenOut: tradeService.tokenOut + ) buyPriceRelay.accept(SwapPriceCell.PriceViewItem(price: prices?.0, revertedPrice: prices?.1)) } else { buyPriceRelay.accept(nil) @@ -154,7 +155,7 @@ class UniswapV3ViewModel { if case .ready = service.state { actionState = .enabled(title: "swap.proceed_button".localized) - } else if let error = service.errors.compactMap({ $0 as? SwapModule.SwapError}).first { + } else if let error = service.errors.compactMap({ $0 as? SwapModule.SwapError }).first { switch error { case .noBalanceIn: actionState = .disabled(title: "swap.not_available_button".localized) case .insufficientBalanceIn: actionState = .disabled(title: "swap.button_error.insufficient_balance".localized) @@ -194,12 +195,12 @@ class UniswapV3ViewModel { } else if case .notReady = tradeService.state { revokeWarning = nil approveStep = .notApproved - } else if service.errors.contains(where: { .insufficientBalanceIn == $0 as? SwapModule.SwapError }) { + } else if service.errors.contains(where: { $0 as? SwapModule.SwapError == .insufficientBalanceIn }) { approveStep = .notApproved } else if revokeWarning != nil { revokeAction = .enabled(title: "button.revoke".localized) approveStep = .revokeRequired - } else if service.errors.contains(where: { .insufficientAllowance == $0 as? SwapModule.SwapError }) { + } else if service.errors.contains(where: { $0 as? SwapModule.SwapError == .insufficientAllowance }) { approveAction = .enabled(title: "button.approve".localized) approveStep = .approveRequired } else if case .approved = pendingAllowanceService.state { @@ -218,8 +219,8 @@ class UniswapV3ViewModel { private func settingsViewItem(settings: UniswapSettings) -> SettingsViewItem { SettingsViewItem(slippage: viewItemHelper.slippage(settings.allowedSlippage), - deadline: viewItemHelper.deadline(settings.ttl), - recipient: settings.recipient?.title) + deadline: viewItemHelper.deadline(settings.ttl), + recipient: settings.recipient?.title) } private func sync(amountType: AmountTypeSwitchService.AmountType) { @@ -232,11 +233,9 @@ class UniswapV3ViewModel { private func sync(toggleAvailable: Bool) { isAmountToggleAvailableRelay.accept(toggleAvailable) } - } extension UniswapV3ViewModel { - var amountTypeSelectorItems: [String] { ["swap.amount_type.coin".localized, currencyManager.baseCurrency.code] } @@ -321,7 +320,7 @@ extension UniswapV3ViewModel { tradeService.switchCoins() } - func onChangeAmountType(index: Int) { + func onChangeAmountType(index _: Int) { switchService.toggle() } @@ -346,7 +345,7 @@ extension UniswapV3ViewModel { } func onTapProceed() { - guard case .ready(let transactionData) = service.state else { + guard case let .ready(transactionData) = service.state else { return } @@ -355,37 +354,36 @@ extension UniswapV3ViewModel { } let swapInfo = SendEvmData.SwapInfo( - estimatedOut: tradeService.amountOut, - estimatedIn: tradeService.amountIn, - slippage: viewItemHelper.slippage(tradeService.settings.allowedSlippage), - deadline: viewItemHelper.deadline(tradeService.settings.ttl), - recipientDomain: tradeService.settings.recipient?.domain, - price: viewItemHelper.sortedPrices( - executionPrice: trade.tradeData.executionPrice, - invertedPrice: trade.tradeData.executionPriceInverted, - tokenIn: tradeService.tokenIn, - tokenOut: tradeService.tokenOut)?.0, - priceImpact: viewItemHelper.priceImpactViewItem(priceImpact: trade.tradeData.priceImpact, impactLevel: trade.impactLevel) + estimatedOut: tradeService.amountOut, + estimatedIn: tradeService.amountIn, + slippage: viewItemHelper.slippage(tradeService.settings.allowedSlippage), + deadline: viewItemHelper.deadline(tradeService.settings.ttl), + recipientDomain: tradeService.settings.recipient?.domain, + price: viewItemHelper.sortedPrices( + executionPrice: trade.tradeData.executionPrice, + invertedPrice: trade.tradeData.executionPriceInverted, + tokenIn: tradeService.tokenIn, + tokenOut: tradeService.tokenOut + )?.0, + priceImpact: viewItemHelper.priceImpactViewItem(priceImpact: trade.tradeData.priceImpact, impactLevel: trade.impactLevel) ) var impactWarning = [Warning]() switch trade.impactLevel { - case .warning: impactWarning = [UniswapModule.UniswapWarning.highPriceImpact] - case .forbidden: impactWarning = [UniswapModule.UniswapWarning.forbiddenPriceImpact] + case .warning: impactWarning = [UniswapModule.UniswapWarning.highPriceImpact] + case .forbidden: impactWarning = [UniswapModule.UniswapWarning.forbiddenPriceImpact] default: () } let sendEvmData = SendEvmData( - transactionData: transactionData, additionalInfo: .uniswap(info: swapInfo), - warnings: impactWarning + transactionData: transactionData, additionalInfo: .uniswap(info: swapInfo), + warnings: impactWarning ) openConfirmRelay.accept(sendEvmData) } - } extension UniswapV3ViewModel { - struct TradeViewItem { let executionPrice: String? let executionPriceInverted: String? @@ -404,5 +402,4 @@ extension UniswapV3ViewModel { case enabled(title: String) case disabled(title: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceCell.swift index 4a26b09173..82e0e8a6a0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceCell.swift @@ -1,6 +1,6 @@ -import UIKit -import RxSwift import RxCocoa +import RxSwift +import UIKit class SwapAllowanceCell: AdditionalDataCellNew { weak var delegate: IDynamicHeightCellDelegate? @@ -21,7 +21,8 @@ class SwapAllowanceCell: AdditionalDataCellNew { subscribe(disposeBag, viewModel.isErrorDriver) { [weak self] in self?.handle(isError: $0) } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -37,5 +38,4 @@ class SwapAllowanceCell: AdditionalDataCellNew { private func handle(isError: Bool) { valueColor = isError ? .themeLucian : .themeGray } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceService.swift index 0ac1fd49f1..2f87cd3907 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceService.swift @@ -1,8 +1,8 @@ -import Foundation import EvmKit -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class SwapAllowanceService { private let spenderAddress: EvmKit.Address @@ -27,42 +27,40 @@ class SwapAllowanceService { self.adapterManager = adapterManager evmKit.lastBlockHeightObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] blockNumber in - self?.sync() - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] _ in + self?.sync() + }) + .disposed(by: disposeBag) } private func sync() { allowanceDisposeBag = DisposeBag() - guard let token = token, let adapter = adapterManager.adapter(for: token) as? IErc20Adapter else { + guard let token, let adapter = adapterManager.adapter(for: token) as? IErc20Adapter else { state = nil return } - if let state = state, case .ready = state { + if let state, case .ready = state { // no need to set loading, simply update to new allowance value } else { state = .loading } adapter - .allowanceSingle(spenderAddress: spenderAddress, defaultBlockParameter: .latest) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] allowance in - self?.state = .ready(allowance: CoinValue(kind: .token(token: token), value: allowance)) - }, onError: { [weak self] error in - self?.state = .notReady(error: error) - }) - .disposed(by: allowanceDisposeBag) + .allowanceSingle(spenderAddress: spenderAddress, defaultBlockParameter: .latest) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] allowance in + self?.state = .ready(allowance: CoinValue(kind: .token(token: token), value: allowance)) + }, onError: { [weak self] error in + self?.state = .notReady(error: error) + }) + .disposed(by: allowanceDisposeBag) } - } extension SwapAllowanceService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -73,36 +71,34 @@ extension SwapAllowanceService { } func approveData(dex: SwapModule.Dex, amount: Decimal) -> ApproveData? { - guard case .ready(let allowance) = state else { + guard case let .ready(allowance) = state else { return nil } - guard let token = token else { + guard let token else { return nil } return ApproveData( - dex: dex, - token: token, - spenderAddress: spenderAddress, - amount: amount, - allowance: allowance.value + dex: dex, + token: token, + spenderAddress: spenderAddress, + amount: amount, + allowance: allowance.value ) } - } extension SwapAllowanceService { - enum State: Equatable { case loading case ready(allowance: CoinValue) case notReady(error: Error) - static func ==(lhs: State, rhs: State) -> Bool { + static func == (lhs: State, rhs: State) -> Bool { switch (lhs, rhs) { case (.loading, .loading): return true - case (.ready(let lhsAllowance), .ready(let rhsAllowance)): return lhsAllowance == rhsAllowance + case let (.ready(lhsAllowance), .ready(rhsAllowance)): return lhsAllowance == rhsAllowance default: return false } } @@ -115,5 +111,4 @@ extension SwapAllowanceService { let amount: Decimal let allowance: Decimal } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceViewModel.swift index e3bd407bf3..121e2047b8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapAllowanceViewModel.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxCocoa +import RxSwift class SwapAllowanceViewModel { private let disposeBag = DisposeBag() @@ -13,6 +13,7 @@ class SwapAllowanceViewModel { isVisibleRelay.accept(isVisible) } } + private var isVisibleRelay = PublishRelay() private var allowanceRelay = BehaviorRelay(value: nil) private var isErrorRelay = BehaviorRelay(value: false) @@ -57,26 +58,24 @@ class SwapAllowanceViewModel { } private func handle(errors: [Error]) { - let error = errors.first(where: { .insufficientAllowance == $0 as? SwapModule.SwapError }) + let error = errors.first(where: { $0 as? SwapModule.SwapError == .insufficientAllowance }) isErrorRelay.accept(error != nil) syncVisible() } private func allowance(state: SwapAllowanceService.State, errors: [Error]) -> String? { - let isInsufficientAllowance = errors.first(where: { .insufficientAllowance == $0 as? SwapModule.SwapError }) != nil + let isInsufficientAllowance = errors.first(where: { $0 as? SwapModule.SwapError == .insufficientAllowance }) != nil switch state { - case .ready(let allowance): + case let .ready(allowance): return isInsufficientAllowance ? ValueFormatter.instance.formatFull(coinValue: allowance) : nil default: return nil } } - } extension SwapAllowanceViewModel { - var isVisibleSignal: Signal { isVisibleRelay.asSignal() } @@ -88,5 +87,4 @@ extension SwapAllowanceViewModel { var isErrorDriver: Driver { isErrorRelay.asDriver() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapPendingAllowanceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapPendingAllowanceService.swift index 72f95ece27..cda7f28ba3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapPendingAllowanceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Allowance/SwapPendingAllowanceService.swift @@ -1,8 +1,8 @@ -import Foundation import EvmKit -import RxSwift -import RxRelay +import Foundation import MarketKit +import RxRelay +import RxSwift class SwapPendingAllowanceService { private let spenderAddress: EvmKit.Address @@ -29,22 +29,22 @@ class SwapPendingAllowanceService { self.allowanceService = allowanceService allowanceService.stateObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] _ in - self?.sync() - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] _ in + self?.sync() + }) + .disposed(by: disposeBag) } private func sync() { // print("Pending allowance: \(pendingAllowance ?? -1)") - guard let pendingAllowance = pendingAllowance else { + guard let pendingAllowance else { state = .notAllowed return } // print("allowance state: \(allowanceService.state)") - guard case .ready(let allowance) = allowanceService.state else { + guard case let .ready(allowance) = allowanceService.state else { state = .notAllowed return } @@ -55,11 +55,9 @@ class SwapPendingAllowanceService { state = .approved } } - } extension SwapPendingAllowanceService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -72,7 +70,7 @@ extension SwapPendingAllowanceService { } func syncAllowance() { - guard let token = token, let adapter = adapterManager.adapter(for: token) as? IErc20Adapter else { + guard let token, let adapter = adapterManager.adapter(for: token) as? IErc20Adapter else { return } @@ -84,13 +82,10 @@ extension SwapPendingAllowanceService { sync() } - } extension SwapPendingAllowanceService { - enum State: Int { case notAllowed, revoking, pending, approved } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/CoinCardModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/CoinCardModule.swift index d80a7c331e..8221957626 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/CoinCardModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/CoinCardModule.swift @@ -1,7 +1,7 @@ import Foundation -import UniswapKit -import RxSwift import MarketKit +import RxSwift +import UniswapKit protocol ISwapCoinCardService: AnyObject { var dex: SwapModule.Dex { get } @@ -23,7 +23,6 @@ protocol ISwapCoinCardService: AnyObject { } extension ISwapCoinCardService { - var readOnly: Bool { false } @@ -31,11 +30,9 @@ extension ISwapCoinCardService { var readOnlyObservable: Observable { Observable.just(false) } - } -struct CoinCardModule { - +enum CoinCardModule { static func fromCell(service: UniswapService, tradeService: UniswapTradeService, switchService: AmountTypeSwitchService) -> SwapCoinCardCell { let coinCardService = SwapFromCoinCardService(service: service, tradeService: tradeService) @@ -45,10 +42,10 @@ struct CoinCardModule { let viewModel = SwapCoinCardViewModel(coinCardService: coinCardService, fiatService: fiatService) let amountInputViewModel = AmountInputViewModel( - service: coinCardService, - fiatService: fiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: coinCardService, + fiatService: fiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) return SwapCoinCardCell(viewModel: viewModel, amountInputViewModel: amountInputViewModel, title: "swap.you_pay".localized) } @@ -62,11 +59,11 @@ struct CoinCardModule { let viewModel = SwapCoinCardViewModel(coinCardService: coinCardService, fiatService: fiatService) let amountInputViewModel = AmountInputViewModel( - service: coinCardService, - fiatService: fiatService, - switchService: switchService, - decimalParser: AmountDecimalParser(), - isMaxSupported: false + service: coinCardService, + fiatService: fiatService, + switchService: switchService, + decimalParser: AmountDecimalParser(), + isMaxSupported: false ) return SwapCoinCardCell(viewModel: viewModel, amountInputViewModel: amountInputViewModel, title: "swap.you_get".localized) } @@ -80,10 +77,10 @@ struct CoinCardModule { let viewModel = SwapCoinCardViewModel(coinCardService: coinCardService, fiatService: fiatService) let amountInputViewModel = AmountInputViewModel( - service: coinCardService, - fiatService: fiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: coinCardService, + fiatService: fiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) return SwapCoinCardCell(viewModel: viewModel, amountInputViewModel: amountInputViewModel, title: "swap.you_pay".localized) } @@ -97,15 +94,14 @@ struct CoinCardModule { let viewModel = SwapCoinCardViewModel(coinCardService: coinCardService, fiatService: fiatService) let amountInputViewModel = AmountInputViewModel( - service: coinCardService, - fiatService: fiatService, - switchService: switchService, - decimalParser: AmountDecimalParser(), - isMaxSupported: false + service: coinCardService, + fiatService: fiatService, + switchService: switchService, + decimalParser: AmountDecimalParser(), + isMaxSupported: false ) return SwapCoinCardCell(viewModel: viewModel, amountInputViewModel: amountInputViewModel, title: "swap.you_get".localized) } - } class SwapFromCoinCardService: ISwapCoinCardService, IAmountInputService { @@ -129,9 +125,10 @@ class SwapFromCoinCardService: ISwapCoinCardService, IAmountInputService { var balanceObservable: Observable { service.balanceInObservable } var errorObservable: Observable { service.errorsObservable.map { - $0.first(where: { .insufficientBalanceIn == $0 as? SwapModule.SwapError }) + $0.first(where: { $0 as? SwapModule.SwapError == .insufficientBalanceIn }) } } + var isLoading: Observable { tradeService.stateObservable.map { state in switch state { @@ -148,7 +145,6 @@ class SwapFromCoinCardService: ISwapCoinCardService, IAmountInputService { func onChange(token: MarketKit.Token) { tradeService.set(tokenIn: token) } - } class SwapToCoinCardService: ISwapCoinCardService, IAmountInputService { @@ -173,6 +169,7 @@ class SwapToCoinCardService: ISwapCoinCardService, IAmountInputService { var errorObservable: Observable { Observable.just(nil) } + var isLoading: Observable { tradeService.stateObservable.map { state in switch state { @@ -184,10 +181,11 @@ class SwapToCoinCardService: ISwapCoinCardService, IAmountInputService { var amountWarningObservable: Observable { tradeService.stateObservable.map { state in - guard case .ready(let trade) = state, + guard case let .ready(trade) = state, let impactLevel = trade.impactLevel, case .forbidden = impactLevel, - let priceImpact = trade.tradeData.priceImpact else { + let priceImpact = trade.tradeData.priceImpact + else { return nil } @@ -202,7 +200,6 @@ class SwapToCoinCardService: ISwapCoinCardService, IAmountInputService { func onChange(token: MarketKit.Token) { tradeService.set(tokenOut: token) } - } class SwapV3FromCoinCardService: ISwapCoinCardService, IAmountInputService { @@ -226,9 +223,10 @@ class SwapV3FromCoinCardService: ISwapCoinCardService, IAmountInputService { var balanceObservable: Observable { service.balanceInObservable } var errorObservable: Observable { service.errorsObservable.map { - $0.first(where: { .insufficientBalanceIn == $0 as? SwapModule.SwapError }) + $0.first(where: { $0 as? SwapModule.SwapError == .insufficientBalanceIn }) } } + var isLoading: Observable { tradeService.stateObservable.map { state in switch state { @@ -245,7 +243,6 @@ class SwapV3FromCoinCardService: ISwapCoinCardService, IAmountInputService { func onChange(token: MarketKit.Token) { tradeService.set(tokenIn: token) } - } class SwapV3ToCoinCardService: ISwapCoinCardService, IAmountInputService { @@ -270,6 +267,7 @@ class SwapV3ToCoinCardService: ISwapCoinCardService, IAmountInputService { var errorObservable: Observable { Observable.just(nil) } + var isLoading: Observable { tradeService.stateObservable.map { state in switch state { @@ -281,10 +279,11 @@ class SwapV3ToCoinCardService: ISwapCoinCardService, IAmountInputService { var amountWarningObservable: Observable { tradeService.stateObservable.map { state in - guard case .ready(let trade) = state, + guard case let .ready(trade) = state, let impactLevel = trade.impactLevel, case .forbidden = impactLevel, - let priceImpact = trade.tradeData.priceImpact else { + let priceImpact = trade.tradeData.priceImpact + else { return nil } @@ -299,7 +298,6 @@ class SwapV3ToCoinCardService: ISwapCoinCardService, IAmountInputService { func onChange(token: MarketKit.Token) { tradeService.set(tokenOut: token) } - } class SwapFromCoinCardOneInchService: ISwapCoinCardService, IAmountInputService { @@ -323,9 +321,10 @@ class SwapFromCoinCardOneInchService: ISwapCoinCardService, IAmountInputService var balanceObservable: Observable { service.balanceInObservable } var errorObservable: Observable { service.errorsObservable.map { - $0.first(where: { .insufficientBalanceIn == $0 as? SwapModule.SwapError }) + $0.first(where: { $0 as? SwapModule.SwapError == .insufficientBalanceIn }) } } + var isLoading: Observable { .just(false) } @@ -337,7 +336,6 @@ class SwapFromCoinCardOneInchService: ISwapCoinCardService, IAmountInputService func onChange(token: MarketKit.Token) { tradeService.set(tokenIn: token) } - } class SwapToCoinCardOneInchService: ISwapCoinCardService, IAmountInputService { @@ -364,6 +362,7 @@ class SwapToCoinCardOneInchService: ISwapCoinCardService, IAmountInputService { var errorObservable: Observable { Observable.just(nil) } + var isLoading: Observable { tradeService.stateObservable.map { state in switch state { @@ -373,12 +372,11 @@ class SwapToCoinCardOneInchService: ISwapCoinCardService, IAmountInputService { } } - func onChange(amount: Decimal) { + func onChange(amount _: Decimal) { // can't change to-card } func onChange(token: MarketKit.Token) { tradeService.set(tokenOut: token) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardCell.swift index 167752e7ae..18c17dc9a3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardCell.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import RxSwift -import MarketKit import ComponentKit +import MarketKit +import RxSwift +import ThemeKit +import UIKit class SwapCoinCardCell: UITableViewCell { let cellHeight: CGFloat = 170 + 2 * .margin12 @@ -115,7 +115,8 @@ class SwapCoinCardCell: UITableViewCell { subscribeToViewModel() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -131,11 +132,9 @@ class SwapCoinCardCell: UITableViewCell { let viewController = CoinSelectModule.viewController(dex: viewModel.dex, delegate: self) presentDelegate?.present(viewController: ThemeNavigationController(rootViewController: viewController)) } - } extension SwapCoinCardCell { - private func set(readOnly: Bool) { formAmountInput.editable = !readOnly } @@ -152,7 +151,7 @@ extension SwapCoinCardCell { tokenIconImageView.image = tokenViewItem.flatMap { UIImage(named: $0.placeholderIconName) } } - if let tokenViewItem = tokenViewItem { + if let tokenViewItem { tokenSelectButton.setTitle(tokenViewItem.title, for: .normal) tokenSelectButton.setTitleColor(.themeLeah, for: .normal) } else { @@ -170,13 +169,10 @@ extension SwapCoinCardCell { balanceView.setTitle(color: color) balanceView.setValue(color: color) } - } extension SwapCoinCardCell: ICoinSelectDelegate { - func didSelect(token: Token) { viewModel.onSelect(token: token) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardViewModel.swift index ec780236aa..704ed64a9d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/CoinCard/SwapCoinCardViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift +import MarketKit import RxCocoa +import RxSwift import UniswapKit -import MarketKit class SwapCoinCardViewModel { private let coinCardService: ISwapCoinCardService @@ -64,7 +64,7 @@ class SwapCoinCardViewModel { return } - guard let balance = balance else { + guard let balance else { balanceRelay.accept("n/a".localized) return } @@ -76,11 +76,9 @@ class SwapCoinCardViewModel { private func sync(error: Error?) { balanceErrorRelay.accept(error != nil) } - } extension SwapCoinCardViewModel { - var dex: SwapModule.Dex { coinCardService.dex } @@ -116,15 +114,12 @@ extension SwapCoinCardViewModel { func onSelect(token: MarketKit.Token) { coinCardService.onChange(token: token) } - } extension SwapCoinCardViewModel { - struct TokenViewItem { let title: String let iconUrlString: String let placeholderIconName: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapModule.swift index 70c420e058..e7ed3906a0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapModule.swift @@ -1,24 +1,24 @@ -import UIKit -import MarketKit import EvmKit +import MarketKit +import RxCocoa +import RxSwift import SectionsTableView import ThemeKit -import RxSwift -import RxCocoa +import UIKit import UniswapKit protocol ISwapDexManager { var dex: SwapModule.Dex? { get } func set(provider: SwapModule.Dex.Provider) - var dexUpdated: Signal<()> { get } + var dexUpdated: Signal { get } } protocol ISwapDataSourceManager { var dataSource: ISwapDataSource? { get } var settingsDataSource: ISwapSettingsDataSource? { get } - var dataSourceUpdated: Signal<()> { get } + var dataSourceUpdated: Signal { get } } protocol ISwapProvider: AnyObject { @@ -34,48 +34,45 @@ protocol ISwapDataSource: AnyObject { var state: SwapModule.DataSourceState { get } - var onOpen: ((_ viewController: UIViewController,_ viaPush: Bool) -> ())? { get set } - var onOpenSelectProvider: (() -> ())? { get set } - var onOpenSettings: (() -> ())? { get set } - var onClose: (() -> ())? { get set } - var onReload: (() -> ())? { get set } + var onOpen: ((_ viewController: UIViewController, _ viaPush: Bool) -> Void)? { get set } + var onOpenSelectProvider: (() -> Void)? { get set } + var onOpenSettings: (() -> Void)? { get set } + var onClose: (() -> Void)? { get set } + var onReload: (() -> Void)? { get set } func viewDidAppear() } -class SwapModule { - +enum SwapModule { static func viewController(tokenFrom: MarketKit.Token? = nil) -> UIViewController? { let swapDexManager = SwapProviderManager(localStorage: App.shared.localStorage, evmBlockchainManager: App.shared.evmBlockchainManager, tokenFrom: tokenFrom) - let viewModel = SwapViewModel(dexManager: swapDexManager) + let viewModel = SwapViewModel(dexManager: swapDexManager) let viewController = SwapViewController( - viewModel: viewModel, - dataSourceManager: swapDexManager + viewModel: viewModel, + dataSourceManager: swapDexManager ) return viewController } - } extension SwapModule { private static let addressesForRevoke = ["0xdac17f958d2ee523a2206206994597c13d831ec7"] static func mustBeRevoked(token: MarketKit.Token?) -> Bool { - if let token = token, + if let token, case .ethereum = token.blockchainType, - case .eip20(let address) = token.type, - Self.addressesForRevoke.contains(address.lowercased()) { + case let .eip20(address) = token.type, + addressesForRevoke.contains(address.lowercased()) + { return true } return false } - } extension SwapModule { - enum ApproveStepState: Int { case notApproved, revokeRequired, revoking, approveRequired, approving, approved } @@ -94,7 +91,6 @@ extension SwapModule { self.amountTo = amountTo self.exactFrom = exactFrom } - } class Dex { @@ -119,42 +115,36 @@ extension SwapModule { self.blockchainType = blockchainType self.provider = provider } - } - } extension SwapModule { - enum SwapError: Error, Equatable { case noBalanceIn case insufficientBalanceIn case insufficientAllowance case needRevokeAllowance(allowance: CoinValue) - static func ==(lhs: SwapError, rhs: SwapError) -> Bool { + static func == (lhs: SwapError, rhs: SwapError) -> Bool { switch (lhs, rhs) { case (.noBalanceIn, .noBalanceIn): return true case (.insufficientBalanceIn, .insufficientBalanceIn): return true case (.insufficientAllowance, .insufficientAllowance): return true - case (.needRevokeAllowance(let lAllowance), .needRevokeAllowance(let rAllowance)): return lAllowance == rAllowance + case let (.needRevokeAllowance(lAllowance), .needRevokeAllowance(rAllowance)): return lAllowance == rAllowance default: return false } } var revokeAllowance: CoinValue? { switch self { - case .needRevokeAllowance(let allowance): return allowance + case let .needRevokeAllowance(allowance): return allowance default: return nil } } - } - } extension BlockchainType { - var allowedProviders: [SwapModule.Dex.Provider] { switch self { case .ethereum: return [.oneInch, .uniswap, .uniswapV3, .pancakeV3] @@ -168,11 +158,9 @@ extension BlockchainType { default: return [] } } - } extension SwapModule.Dex { - enum Provider: String { case uniswap = "Uniswap" case uniswapV3 = "Uniswap V3" @@ -238,9 +226,7 @@ extension SwapModule.Dex { default: return .pancakeSwap } } - } - } protocol ISwapErrorProvider { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapProviderManager.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapProviderManager.swift index 969b379d1c..d55b7725d0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapProviderManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapProviderManager.swift @@ -34,7 +34,7 @@ class SwapProviderManager { private func initSectionsDataSource(tokenFrom: MarketKit.Token?) { let blockchainType: BlockchainType - if let tokenFrom = tokenFrom { + if let tokenFrom { if let type = evmBlockchainManager.blockchain(token: tokenFrom)?.type { blockchainType = type } else { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewController.swift index c181cc8950..4c7d3f6992 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit -import UniswapKit +import ComponentKit import HUD -import RxSwift import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import ThemeKit +import UIKit +import UniswapKit class SwapViewController: ThemeViewController { private let animationDuration: TimeInterval = 0.2 @@ -27,7 +27,8 @@ class SwapViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -105,10 +106,10 @@ class SwapViewController: ThemeViewController { } @objc func onOpenSettings() { - guard let viewController = SwapSettingsModule.viewController( - dataSourceManager: dataSourceManager, - dexManager: viewModel.dexManager) else { - + guard let viewController = SwapSettingsModule.viewController( + dataSourceManager: dataSourceManager, + dexManager: viewModel.dexManager + ) else { return } @@ -131,20 +132,16 @@ class SwapViewController: ThemeViewController { tableView.endUpdates() } } - } extension SwapViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let dataSource = dataSource { + if let dataSource { sections.append(contentsOf: dataSource.buildSections) } return sections } - } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewModel.swift index 93d9b8e65f..662b931631 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/SwapViewModel.swift @@ -6,5 +6,4 @@ class SwapViewModel { init(dexManager: ISwapDexManager) { self.dexManager = dexManager } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/StepBadgeView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/StepBadgeView.swift index 9e0db48b0e..6fce300ed3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/StepBadgeView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/StepBadgeView.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class StepBadgeView: UIView { private let label = UILabel() @@ -19,7 +19,8 @@ class StepBadgeView: UIView { layer.cornerRadius = .cornerRadius12 } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -32,5 +33,4 @@ class StepBadgeView: UIView { get { label.text } set { label.text = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapStepCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapStepCell.swift index 289261e3b0..e934daf236 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapStepCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapStepCell.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class SwapStepCell: UITableViewCell { private let firstStepView = StepBadgeView() @@ -45,7 +45,6 @@ class SwapStepCell: UITableViewCell { lastStepView.text = "2" lastStepView.set(active: false) - } required init?(coder aDecoder: NSCoder) { @@ -60,5 +59,4 @@ class SwapStepCell: UITableViewCell { var cellHeight: CGFloat { isVisible ? 24 : 0 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapSwitchCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapSwitchCell.swift index a96ec54f2b..d5a19cc010 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapSwitchCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Swap/Views/SwapSwitchCell.swift @@ -1,8 +1,8 @@ -import UIKit import ComponentKit -import ThemeKit -import RxSwift import HUD +import RxSwift +import ThemeKit +import UIKit class SwapSwitchCell: UITableViewCell { let cellHeight: CGFloat = 24 @@ -10,9 +10,9 @@ class SwapSwitchCell: UITableViewCell { private let spinner = HUDActivityView.create(with: .medium24) private let switchButton = UIButton() - var onSwitch: (() -> ())? + var onSwitch: (() -> Void)? - override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style _: UITableViewCell.CellStyle, reuseIdentifier _: String?) { super.init(style: .default, reuseIdentifier: nil) backgroundColor = .clear @@ -40,7 +40,8 @@ class SwapSwitchCell: UITableViewCell { switchButton.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -56,5 +57,4 @@ class SwapSwitchCell: UITableViewCell { spinner.stopAnimating() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationModule.swift index 2d48f4a369..a9d7e5b401 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationModule.swift @@ -1,27 +1,26 @@ -import UIKit -import ThemeKit -import EvmKit import BigInt +import EvmKit import HsExtensions +import ThemeKit +import UIKit struct SwapApproveConfirmationModule { - static func viewController(sendData: SendEvmData, dex: SwapModule.Dex, revokeAllowance: Bool = false, delegate: ISwapApproveDelegate?) -> UIViewController? { guard let evmKitWrapper = App.shared.evmBlockchainManager.evmKitManager(blockchainType: dex.blockchainType).evmKitWrapper else { return nil } guard let coinServiceFactory = EvmCoinServiceFactory( - blockchainType: dex.blockchainType, - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - coinManager: App.shared.coinManager + blockchainType: dex.blockchainType, + marketKit: App.shared.marketKit, + currencyManager: App.shared.currencyManager, + coinManager: App.shared.coinManager ) else { return nil } guard let (settingsService, settingsViewModel) = EvmSendSettingsModule.instance( - evmKit: evmKitWrapper.evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory + evmKit: evmKitWrapper.evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory ) else { return nil } @@ -42,10 +41,10 @@ struct SwapApproveConfirmationModule { } let service = SwapApproveService( - eip20Kit: eip20Adapter.eip20Kit, - amount: BigUInt(data.amount.hs.roundedString(decimal: data.token.decimals)) ?? 0, - spenderAddress: data.spenderAddress, - allowance: 0 + eip20Kit: eip20Adapter.eip20Kit, + amount: BigUInt(data.amount.hs.roundedString(decimal: data.token.decimals)) ?? 0, + spenderAddress: data.spenderAddress, + allowance: 0 ) guard case let .approveAllowed(sendData) = service.state else { @@ -59,6 +58,4 @@ struct SwapApproveConfirmationModule { return ThemeNavigationController(rootViewController: confirmationController) } - - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationViewController.swift index 1bfeea35c2..f56cc72abc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapApproveConfirmationViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import SnapKit -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class SwapApproveConfirmationViewController: SendEvmTransactionViewController { private let approveButton = PrimaryButton() @@ -15,7 +15,8 @@ class SwapApproveConfirmationViewController: SendEvmTransactionViewController { super.init(transactionViewModel: transactionViewModel, settingsViewModel: settingsViewModel) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -47,5 +48,4 @@ class SwapApproveConfirmationViewController: SendEvmTransactionViewController { super.handleSendSuccess(transactionHash: transactionHash) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapRevokeConfirmationViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapRevokeConfirmationViewController.swift index 39a79846e3..a2d15e1297 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapRevokeConfirmationViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Confirmation/SwapRevokeConfirmationViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import SnapKit -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class SwapRevokeConfirmationViewController: SendEvmTransactionViewController { private let approveButton = PrimaryButton() @@ -16,7 +16,8 @@ class SwapRevokeConfirmationViewController: SendEvmTransactionViewController { super.init(transactionViewModel: transactionViewModel, settingsViewModel: settingsViewModel) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -58,5 +59,4 @@ class SwapRevokeConfirmationViewController: SendEvmTransactionViewController { super.handleSendSuccess(transactionHash: transactionHash) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveModule.swift index 30505c4ddd..910b188005 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveModule.swift @@ -1,40 +1,38 @@ -import UIKit -import EvmKit -import ThemeKit import BigInt +import EvmKit import HsExtensions +import ThemeKit +import UIKit struct SwapApproveModule { - static func instance(data: SwapAllowanceService.ApproveData, delegate: ISwapApproveDelegate) -> UIViewController? { guard let eip20Adapter = App.shared.adapterManager.adapter(for: data.token) as? Eip20Adapter else { return nil } let coinService = CoinService( - token: data.token, - currencyManager: App.shared.currencyManager, - marketKit: App.shared.marketKit + token: data.token, + currencyManager: App.shared.currencyManager, + marketKit: App.shared.marketKit ) let service = SwapApproveService( - eip20Kit: eip20Adapter.eip20Kit, - amount: BigUInt(data.amount.hs.roundedString(decimal: data.token.decimals)) ?? 0, - spenderAddress: data.spenderAddress, - allowance: BigUInt(data.allowance.hs.roundedString(decimal: data.token.decimals)) ?? 0 + eip20Kit: eip20Adapter.eip20Kit, + amount: BigUInt(data.amount.hs.roundedString(decimal: data.token.decimals)) ?? 0, + spenderAddress: data.spenderAddress, + allowance: BigUInt(data.allowance.hs.roundedString(decimal: data.token.decimals)) ?? 0 ) let decimalParser = AmountDecimalParser() let viewModel = SwapApproveViewModel(service: service, coinService: coinService, decimalParser: decimalParser) let viewController = SwapApproveViewController( - viewModel: viewModel, - delegate: delegate, - dex: data.dex + viewModel: viewModel, + delegate: delegate, + dex: data.dex ) return ThemeNavigationController(rootViewController: viewController) } - } protocol ISwapApproveDelegate: AnyObject { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveService.swift index 9cc1fd8a8e..47a72618e4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveService.swift @@ -1,9 +1,9 @@ +import BigInt +import Eip20Kit +import EvmKit import Foundation import RxCocoa import RxSwift -import EvmKit -import Eip20Kit -import BigInt class SwapApproveService { private let disposeBag = DisposeBag() @@ -18,6 +18,7 @@ class SwapApproveService { stateRelay.accept(state) } } + private let stateRelay = BehaviorRelay(value: .approveNotAllowed(errors: [])) init(eip20Kit: Eip20Kit.Kit, amount: BigUInt, spenderAddress: EvmKit.Address, allowance: BigUInt) { @@ -30,23 +31,23 @@ class SwapApproveService { } private func syncState() { - guard let amount = amount else { + guard let amount else { state = .approveNotAllowed(errors: []) return } var errors = [Error]() - if allowance >= amount && amount > 0 { // 0 amount is used for USDT to drop existing allowance + if allowance >= amount, amount > 0 { // 0 amount is used for USDT to drop existing allowance errors.append(TransactionAmountError.alreadyApproved) } if errors.isEmpty { let eip20KitTransactionData = eip20Kit.approveTransactionData(spenderAddress: spenderAddress, amount: amount) let transactionData = TransactionData( - to: eip20KitTransactionData.to, - value: eip20KitTransactionData.value, - input: eip20KitTransactionData.input + to: eip20KitTransactionData.to, + value: eip20KitTransactionData.value, + input: eip20KitTransactionData.input ) state = .approveAllowed(transactionData: transactionData) @@ -54,11 +55,9 @@ class SwapApproveService { state = .approveNotAllowed(errors: errors) } } - } extension SwapApproveService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -68,11 +67,9 @@ extension SwapApproveService { syncState() } - } extension SwapApproveService { - enum State { case approveNotAllowed(errors: [Error]) case approveAllowed(transactionData: TransactionData) @@ -81,5 +78,4 @@ extension SwapApproveService { enum TransactionAmountError: Error { case alreadyApproved } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewController.swift index f99cdda786..0cbd0a51cc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit +import EvmKit import RxSwift import SectionsTableView -import EvmKit +import ThemeKit +import UIKit class SwapApproveViewController: KeyboardAwareViewController { private let disposeBag = DisposeBag() @@ -27,7 +27,8 @@ class SwapApproveViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -96,58 +97,54 @@ class SwapApproveViewController: KeyboardAwareViewController { navigationController?.pushViewController(viewController, animated: true) } - } extension SwapApproveViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "main", - rows: [ - tableView.highlightedDescriptionRow(id: "description", text: "swap.approve.description".localized) - ] + id: "main", + rows: [ + tableView.highlightedDescriptionRow(id: "description", text: "swap.approve.description".localized), + ] ), Section( - id: "amount", - headerState: .margin(height: CGFloat.margin16), - rows: [ - StaticRow( - cell: amountCell, - id: "amount", - dynamicHeight: { [weak self] width in - self?.amountCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: amountCautionCell, - id: "amount-caution", - dynamicHeight: { [weak self] width in - self?.amountCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "amount", + headerState: .margin(height: CGFloat.margin16), + rows: [ + StaticRow( + cell: amountCell, + id: "amount", + dynamicHeight: { [weak self] width in + self?.amountCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: amountCautionCell, + id: "amount-caution", + dynamicHeight: { [weak self] width in + self?.amountCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "approve_button", - headerState: .margin(height: .margin8), - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: buttonCell, - id: "approve-button", - height: PrimaryButtonCell.height - ) - ] - ) + id: "approve_button", + headerState: .margin(height: .margin8), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: buttonCell, + id: "approve-button", + height: PrimaryButtonCell.height + ), + ] + ), ] } - } extension SwapApproveViewController: IDynamicHeightCellDelegate { - func onChangeHeight() { guard isLoaded else { return @@ -158,5 +155,4 @@ extension SwapApproveViewController: IDynamicHeightCellDelegate { self?.tableView.endUpdates() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewModel.swift index 8371650948..35653c3e63 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/SwapApproveViewModel.swift @@ -1,8 +1,8 @@ +import BigInt +import EvmKit import Foundation import RxCocoa import RxSwift -import EvmKit -import BigInt class SwapApproveViewModel { private let maxCoinDecimals = 8 @@ -24,11 +24,11 @@ class SwapApproveViewModel { self.decimalParser = decimalParser service.stateObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] approveState in - self?.handle(approveState: approveState) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] approveState in + self?.handle(approveState: approveState) + }) + .disposed(by: disposeBag) } private func handle(approveState: SwapApproveService.State) { @@ -40,7 +40,7 @@ class SwapApproveViewModel { var amountCaution: Caution? - if case .approveNotAllowed(var errors) = approveState { + if case var .approveNotAllowed(errors) = approveState { if let balanceErrorIndex = errors.firstIndex(where: { $0 is SwapApproveService.TransactionAmountError }) { let errorString = convert(error: errors.remove(at: balanceErrorIndex)) amountCaution = Caution(text: errorString, type: .error) @@ -57,11 +57,9 @@ class SwapApproveViewModel { return error.convertedError.smartDescription } - } extension SwapApproveViewModel { - var initialAmount: String? { service.amount.map { coinService.monetaryValue(value: $0).description } } @@ -89,17 +87,16 @@ extension SwapApproveViewModel { func onChange(amount: String?) { let amount = decimalParser.parseAnyDecimal(from: amount) - .map { coinService.fractionalMonetaryValue(value: $0) } + .map { coinService.fractionalMonetaryValue(value: $0) } service.set(amount: amount) } func proceed() { - guard case .approveAllowed(let transactionData) = service.state else { + guard case let .approveAllowed(transactionData) = service.state else { return } proceedRelay.accept(transactionData) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Views/SwapApproveAmountView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Views/SwapApproveAmountView.swift index 12d1f53ced..c26d3772c4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Views/SwapApproveAmountView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapApprove/Views/SwapApproveAmountView.swift @@ -31,7 +31,8 @@ class SwapApproveAmountView: UIView { descriptionLabel.textAlignment = .right } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -39,5 +40,4 @@ class SwapApproveAmountView: UIView { amountLabel.text = amount descriptionLabel.text = description } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchFeeService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchFeeService.swift index 3368bafe6d..11c482ad8d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchFeeService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchFeeService.swift @@ -1,10 +1,10 @@ +import BigInt +import EvmKit import Foundation import MarketKit -import RxSwift -import RxRelay -import EvmKit import OneInchKit -import BigInt +import RxRelay +import RxSwift struct OneInchSwapParameters: Equatable { let tokenFrom: MarketKit.Token @@ -14,15 +14,14 @@ struct OneInchSwapParameters: Equatable { let slippage: Decimal let recipient: Address? - static func ==(lhs: OneInchSwapParameters, rhs: OneInchSwapParameters) -> Bool { + static func == (lhs: OneInchSwapParameters, rhs: OneInchSwapParameters) -> Bool { lhs.tokenFrom == rhs.tokenFrom && - lhs.tokenTo == rhs.tokenTo && - lhs.amountFrom == rhs.amountFrom && - lhs.amountTo == rhs.amountTo && - lhs.slippage == rhs.slippage && - lhs.recipient == rhs.recipient + lhs.tokenTo == rhs.tokenTo && + lhs.amountFrom == rhs.amountFrom && + lhs.amountTo == rhs.amountTo && + lhs.slippage == rhs.slippage && + lhs.recipient == rhs.recipient } - } class OneInchFeeService { @@ -66,8 +65,8 @@ class OneInchFeeService { private func sync(gasPriceStatus: DataStatus>) { switch gasPriceStatus { case .loading: status = .loading - case .failed(let error): status = .failed(error) - case .completed(let fallibleGasPrice): sync(fallibleGasPrice: fallibleGasPrice) + case let .failed(error): status = .failed(error) + case let .completed(fallibleGasPrice): sync(fallibleGasPrice: fallibleGasPrice) } } @@ -77,26 +76,26 @@ class OneInchFeeService { let recipient: EvmKit.Address? = parameters.recipient.flatMap { try? EvmKit.Address(hex: $0.raw) } provider.swapSingle( - tokenFrom: parameters.tokenFrom, - tokenTo: parameters.tokenTo, - amount: parameters.amountFrom, - recipient: recipient, - slippage: parameters.slippage, - gasPrice: fallibleGasPrice.data.userDefined - ) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] swap in - self?.sync(swap: swap, fallibleGasPrice: fallibleGasPrice) - }, onError: { [weak self] error in - self?.onSwap(error: error, fallibleGasPrice: fallibleGasPrice) - }) - .disposed(by: disposeBag) + tokenFrom: parameters.tokenFrom, + tokenTo: parameters.tokenTo, + amount: parameters.amountFrom, + recipient: recipient, + slippage: parameters.slippage, + gasPrice: fallibleGasPrice.data.userDefined + ) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] swap in + self?.sync(swap: swap, fallibleGasPrice: fallibleGasPrice) + }, onError: { [weak self] error in + self?.onSwap(error: error, fallibleGasPrice: fallibleGasPrice) + }) + .disposed(by: disposeBag) } private func onSwap(error: Error, fallibleGasPrice: FallibleData) { parameters.amountTo = 0 - if let error = error as? OneInchKit.Kit.SwapError, error == .cannotEstimate { // retry request fee every 5 seconds if cannot estimate + if let error = error as? OneInchKit.Kit.SwapError, error == .cannotEstimate { // retry request fee every 5 seconds if cannot estimate let retryTimer = Observable.just(()).delay(.seconds(Self.retryInterval), scheduler: ConcurrentDispatchQueueScheduler(qos: .userInitiated)) subscribe(retryDisposeBag, retryTimer) { [weak self] in @@ -123,18 +122,15 @@ class OneInchFeeService { } status = .completed(FallibleData( - data: EvmFeeModule.Transaction(transactionData: transactionData, gasData: gasData), - errors: errors, - warnings: fallibleGasPrice.warnings + data: EvmFeeModule.Transaction(transactionData: transactionData, gasData: gasData), + errors: errors, + warnings: fallibleGasPrice.warnings )) } - } extension OneInchFeeService: IEvmFeeService { - var statusObservable: Observable>> { transactionStatusRelay.asObservable() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchSendEvmTransactionService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchSendEvmTransactionService.swift index 7daa7ff8a5..8dadfbb3fb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchSendEvmTransactionService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/OneInch/OneInchSendEvmTransactionService.swift @@ -1,13 +1,11 @@ -import Foundation -import RxSwift -import RxCocoa -import EvmKit import BigInt +import EvmKit +import Foundation import MarketKit import OneInchKit +import RxCocoa +import RxSwift import UniswapKit -import EvmKit -import BigInt class OneInchSendEvmTransactionService { private let disposeBag = DisposeBag() @@ -23,7 +21,7 @@ class OneInchSendEvmTransactionService { } } - private(set) var dataState: SendEvmTransactionService.DataState = SendEvmTransactionService.DataState(transactionData: nil, additionalInfo: nil, decoration: nil, nonce: nil) + private(set) var dataState: SendEvmTransactionService.DataState = .init(transactionData: nil, additionalInfo: nil, decoration: nil, nonce: nil) private let sendStateRelay = PublishRelay() private(set) var sendState: SendEvmTransactionService.SendState = .idle { @@ -41,10 +39,10 @@ class OneInchSendEvmTransactionService { // show initial info from parameters dataState = SendEvmTransactionService.DataState( - transactionData: nil, - additionalInfo: additionalInfo(parameters: oneInchFeeService.parameters), - decoration: nil, - nonce: nil + transactionData: nil, + additionalInfo: additionalInfo(parameters: oneInchFeeService.parameters), + decoration: nil, + nonce: nil ) } @@ -56,16 +54,16 @@ class OneInchSendEvmTransactionService { switch status { case .loading: state = .notReady(errors: [], warnings: []) - case .failed(let error): + case let .failed(error): state = .notReady(errors: [error], warnings: []) - case .completed(let fallibleTransaction): + case let .completed(fallibleTransaction): let transaction = fallibleTransaction.data dataState = SendEvmTransactionService.DataState( - transactionData: transaction.transactionData, - additionalInfo: additionalInfo(parameters: oneInchFeeService.parameters), - decoration: evmKit.decorate(transactionData: transaction.transactionData), - nonce: settingsService.nonceService.frozen ? settingsService.nonceService.nonce : nil + transactionData: transaction.transactionData, + additionalInfo: additionalInfo(parameters: oneInchFeeService.parameters), + decoration: evmKit.decorate(transactionData: transaction.transactionData), + nonce: settingsService.nonceService.frozen ? settingsService.nonceService.nonce : nil ) if fallibleTransaction.errors.isEmpty { @@ -88,11 +86,9 @@ class OneInchSendEvmTransactionService { ) ) } - } extension OneInchSendEvmTransactionService: ISendEvmTransactionService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -105,12 +101,12 @@ extension OneInchSendEvmTransactionService: ISendEvmTransactionService { evmKit.receiveAddress } - func methodName(input: Data) -> String? { + func methodName(input _: Data) -> String? { nil } func send() { - guard case .ready = state, case .completed(let fallibleTransaction) = settingsService.status else { + guard case .ready = state, case let .completed(fallibleTransaction) = settingsService.status else { return } let transaction = fallibleTransaction.data @@ -118,18 +114,17 @@ extension OneInchSendEvmTransactionService: ISendEvmTransactionService { sendState = .sending evmKitWrapper.sendSingle( - transactionData: transaction.transactionData, - gasPrice: transaction.gasData.price, - gasLimit: transaction.gasData.limit, - nonce: transaction.nonce - ) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onSuccess: { [weak self] fullTransaction in - self?.sendState = .sent(transactionHash: fullTransaction.transaction.hash) - }, onError: { error in - self.sendState = .failed(error: error) - }) - .disposed(by: disposeBag) + transactionData: transaction.transactionData, + gasPrice: transaction.gasData.price, + gasLimit: transaction.gasData.limit, + nonce: transaction.nonce + ) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onSuccess: { [weak self] fullTransaction in + self?.sendState = .sent(transactionHash: fullTransaction.transaction.hash) + }, onError: { error in + self.sendState = .failed(error: error) + }) + .disposed(by: disposeBag) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationAmountCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationAmountCell.swift index a579e2816d..28d9efeab3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationAmountCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationAmountCell.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class SwapConfirmationAmountCell: BaseThemeCell { static let height: CGFloat = 72 @@ -64,7 +64,8 @@ class SwapConfirmationAmountCell: BaseThemeCell { getValueLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -75,5 +76,4 @@ class SwapConfirmationAmountCell: BaseThemeCell { getTitleLabel.text = getTitle getValueLabel.text = getValue } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationModule.swift index 518df6f5ac..5f8a3c4cfe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationModule.swift @@ -1,26 +1,25 @@ -import UIKit -import ThemeKit import EvmKit import OneInchKit +import ThemeKit +import UIKit struct SwapConfirmationModule { - static func viewController(sendData: SendEvmData, dex: SwapModule.Dex) -> UIViewController? { - guard let evmKitWrapper = App.shared.evmBlockchainManager.evmKitManager(blockchainType: dex.blockchainType).evmKitWrapper else { + guard let evmKitWrapper = App.shared.evmBlockchainManager.evmKitManager(blockchainType: dex.blockchainType).evmKitWrapper else { return nil } guard let coinServiceFactory = EvmCoinServiceFactory( - blockchainType: dex.blockchainType, - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - coinManager: App.shared.coinManager + blockchainType: dex.blockchainType, + marketKit: App.shared.marketKit, + currencyManager: App.shared.currencyManager, + coinManager: App.shared.coinManager ) else { return nil } guard let (settingsService, settingsViewModel) = EvmSendSettingsModule.instance( - evmKit: evmKitWrapper.evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory + evmKit: evmKitWrapper.evmKit, blockchainType: evmKitWrapper.blockchainType, sendData: sendData, coinServiceFactory: coinServiceFactory ) else { return nil } @@ -33,23 +32,24 @@ struct SwapConfirmationModule { } static func viewController(parameters: OneInchSwapParameters, dex: SwapModule.Dex) -> UIViewController? { - guard let evmKitWrapper = App.shared.evmBlockchainManager.evmKitManager(blockchainType: dex.blockchainType).evmKitWrapper else { + guard let evmKitWrapper = App.shared.evmBlockchainManager.evmKitManager(blockchainType: dex.blockchainType).evmKitWrapper else { return nil } let evmKit = evmKitWrapper.evmKit guard let apiKey = AppConfig.oneInchApiKey, - let swapKit = try? OneInchKit.Kit.instance(evmKit: evmKit, apiKey: apiKey) else { + let swapKit = try? OneInchKit.Kit.instance(evmKit: evmKit, apiKey: apiKey) + else { return nil } let oneInchProvider = OneInchProvider(swapKit: swapKit) guard let coinServiceFactory = EvmCoinServiceFactory( - blockchainType: dex.blockchainType, - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - coinManager: App.shared.coinManager + blockchainType: dex.blockchainType, + marketKit: App.shared.marketKit, + currencyManager: App.shared.currencyManager, + coinManager: App.shared.coinManager ) else { return nil } @@ -58,7 +58,7 @@ struct SwapConfirmationModule { let coinService = coinServiceFactory.baseCoinService let feeViewItemFactory = FeeViewItemFactory(scale: coinService.token.blockchainType.feePriceScale) let nonceService = NonceService(evmKit: evmKit, replacingNonce: nil) - let feeService = OneInchFeeService(evmKit: evmKit, provider: oneInchProvider, gasPriceService: gasPriceService, coinService: coinServiceFactory.baseCoinService, parameters: parameters) + let feeService = OneInchFeeService(evmKit: evmKit, provider: oneInchProvider, gasPriceService: gasPriceService, coinService: coinServiceFactory.baseCoinService, parameters: parameters) let settingsService = EvmSendSettingsService(feeService: feeService, nonceService: nonceService) let cautionsFactory = SendEvmCautionsFactory() @@ -83,5 +83,4 @@ struct SwapConfirmationModule { return SwapConfirmationViewController(transactionViewModel: transactionViewModel, settingsViewModel: settingsViewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationViewController.swift index 9451711e42..61ca7b7889 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapConfirmation/SwapConfirmationViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import SnapKit -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class SwapConfirmationViewController: SendEvmTransactionViewController { private let swapButton = SliderButton() @@ -41,5 +41,4 @@ class SwapConfirmationViewController: SendEvmTransactionViewController { swapButton.reset() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputAccessoryView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputAccessoryView.swift index 28ce8ccddd..4011f551f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputAccessoryView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputAccessoryView.swift @@ -11,7 +11,7 @@ class SwapInputAccessoryView: UIView { } } - var onSelect: ((Decimal) -> ())? + var onSelect: ((Decimal) -> Void)? override public init(frame: CGRect) { super.init(frame: frame) @@ -36,10 +36,11 @@ class SwapInputAccessoryView: UIView { FilterView.ViewItem.item(title: "75%"), FilterView.ViewItem.item(title: "100%"), ]) - autocompleteView.onSelect = {[weak self] in self?.onTap(at: $0) } + autocompleteView.onSelect = { [weak self] in self?.onTap(at: $0) } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -63,5 +64,4 @@ class SwapInputAccessoryView: UIView { let multi = 0.25 * Decimal(index + 1) onSelect?(multi) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCardView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCardView.swift index 323cb88c80..ecfe0d35db 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCardView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCardView.swift @@ -1,10 +1,10 @@ +import ComponentKit import Foundation -import UIKit +import MarketKit import RxSwift import SnapKit import ThemeKit -import ComponentKit -import MarketKit +import UIKit class SwapInputCardView: UIView { static let lineHeight: CGFloat = 90 @@ -42,7 +42,7 @@ class SwapInputCardView: UIView { if isTopView { autocompleteView = SwapInputAccessoryView(frame: .zero) - autocompleteView?.onSelect = { [weak self] multi in self?.setBalance(multi: multi) } + autocompleteView?.onSelect = { [weak self] multi in self?.setBalance(multi: multi) } } addSubview(amountTextView) @@ -56,7 +56,7 @@ class SwapInputCardView: UIView { amountTextView.textColor = .themeLeah amountTextView.placeholder = "0.0" amountTextView.keyboardType = .decimalPad - amountTextView.onChangeEditing = { [weak self] in self?.sync(editing: $0) } + amountTextView.onChangeEditing = { [weak self] in self?.sync(editing: $0) } addSubview(secondaryView) secondaryView.snp.makeConstraints { maker in @@ -105,7 +105,8 @@ class SwapInputCardView: UIView { subscribe(disposeBag, amountInputViewModel.secondaryTextDriver) { [weak self] in self?.set(secondaryText: $0) } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -121,11 +122,9 @@ class SwapInputCardView: UIView { private func sync(editing: Bool) { viewModel.viewIsEditing = editing } - } extension SwapInputCardView { - private func set(readOnly: Bool) { amountTextView.isEditable = !readOnly } @@ -145,7 +144,7 @@ extension SwapInputCardView { tokenSelectView.tokenImage.imageView.image = tokenViewItem.flatMap { UIImage(named: $0.placeholderIconName) } ?? UIImage(named: "placeholder_circle_32") } - if let tokenViewItem = tokenViewItem { + if let tokenViewItem { tokenSelectView.tokenButton.setTitle(tokenViewItem.title, for: .normal) tokenSelectView.tokenButton.setTitleColor(.themeLeah, for: .normal) } else { @@ -154,7 +153,7 @@ extension SwapInputCardView { } } - private func sync(balance: String?) { + private func sync(balance _: String?) { syncAutocompleteHeight() } @@ -165,7 +164,7 @@ extension SwapInputCardView { private func set(amount: String?) { syncAutocompleteHeight() - guard amountTextView.text != amount && !amountInputViewModel.equalValue(lhs: amountTextView.text, rhs: amount) else { //avoid issue with point ("1" and "1.") + guard amountTextView.text != amount, !amountInputViewModel.equalValue(lhs: amountTextView.text, rhs: amount) else { // avoid issue with point ("1" and "1.") return } amountTextView.text = amount @@ -179,13 +178,10 @@ extension SwapInputCardView { private func set(secondaryText: String?) { secondaryView.text = secondaryText } - } extension SwapInputCardView: ICoinSelectDelegate { - func didSelect(token: Token) { viewModel.onSelect(token: token) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCell.swift index 0936200be8..0a8d901685 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputCell.swift @@ -1,9 +1,9 @@ +import ComponentKit import Foundation -import UIKit import RxSwift import SnapKit import ThemeKit -import ComponentKit +import UIKit class SwapInputCell: UITableViewCell { static let cellHeight: CGFloat = 180 @@ -20,7 +20,7 @@ class SwapInputCell: UITableViewCell { private let toInputCard: SwapInputCardView - var onSwitch: (() -> ())? + var onSwitch: (() -> Void)? weak var presentDelegate: IPresentDelegate? { didSet { @@ -88,7 +88,8 @@ class SwapInputCell: UITableViewCell { cardView.bringSubviewToFront(switchButton) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -99,9 +100,6 @@ class SwapInputCell: UITableViewCell { @objc private func onTapSwitch() { onSwitch?() } - } -extension SwapInputCell { - -} +extension SwapInputCell {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputModule.swift index c934c62c53..c5e911fc8d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/SwapInputModule.swift @@ -1,7 +1,6 @@ import Foundation class SwapInputModule { - static func cell(service: UniswapService, tradeService: UniswapTradeService, switchService: AmountTypeSwitchService) -> SwapInputCell { let fromCoinCardService = SwapFromCoinCardService(service: service, tradeService: tradeService) let toCoinCardService = SwapToCoinCardService(service: service, tradeService: tradeService) @@ -15,23 +14,22 @@ class SwapInputModule { let toViewModel = SwapCoinCardViewModel(coinCardService: toCoinCardService, fiatService: toFiatService) let fromAmountInputViewModel = AmountInputViewModel( - service: fromCoinCardService, - fiatService: fromFiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: fromCoinCardService, + fiatService: fromFiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) let toAmountInputViewModel = AmountInputViewModel( - service: toCoinCardService, - fiatService: toFiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: toCoinCardService, + fiatService: toFiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) return SwapInputCell(fromViewModel: fromViewModel, - fromAmountInputViewModel: fromAmountInputViewModel, - toViewModel: toViewModel, - toAmountInputViewModel: toAmountInputViewModel - ) + fromAmountInputViewModel: fromAmountInputViewModel, + toViewModel: toViewModel, + toAmountInputViewModel: toAmountInputViewModel) } static func cell(service: UniswapV3Service, tradeService: UniswapV3TradeService, switchService: AmountTypeSwitchService) -> SwapInputCell { @@ -47,23 +45,22 @@ class SwapInputModule { let toViewModel = SwapCoinCardViewModel(coinCardService: toCoinCardService, fiatService: toFiatService) let fromAmountInputViewModel = AmountInputViewModel( - service: fromCoinCardService, - fiatService: fromFiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: fromCoinCardService, + fiatService: fromFiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) let toAmountInputViewModel = AmountInputViewModel( - service: toCoinCardService, - fiatService: toFiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: toCoinCardService, + fiatService: toFiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) return SwapInputCell(fromViewModel: fromViewModel, - fromAmountInputViewModel: fromAmountInputViewModel, - toViewModel: toViewModel, - toAmountInputViewModel: toAmountInputViewModel - ) + fromAmountInputViewModel: fromAmountInputViewModel, + toViewModel: toViewModel, + toAmountInputViewModel: toAmountInputViewModel) } static func cell(service: OneInchService, tradeService: OneInchTradeService, switchService: AmountTypeSwitchService) -> SwapInputCell { @@ -79,23 +76,21 @@ class SwapInputModule { let toViewModel = SwapCoinCardViewModel(coinCardService: toCoinCardService, fiatService: toFiatService) let fromAmountInputViewModel = AmountInputViewModel( - service: fromCoinCardService, - fiatService: fromFiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: fromCoinCardService, + fiatService: fromFiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) let toAmountInputViewModel = AmountInputViewModel( - service: toCoinCardService, - fiatService: toFiatService, - switchService: switchService, - decimalParser: AmountDecimalParser() + service: toCoinCardService, + fiatService: toFiatService, + switchService: switchService, + decimalParser: AmountDecimalParser() ) return SwapInputCell(fromViewModel: fromViewModel, - fromAmountInputViewModel: fromAmountInputViewModel, - toViewModel: toViewModel, - toAmountInputViewModel: toAmountInputViewModel - ) + fromAmountInputViewModel: fromAmountInputViewModel, + toViewModel: toViewModel, + toAmountInputViewModel: toAmountInputViewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/TokenSelectView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/TokenSelectView.swift index 855f000666..6e396c3949 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/TokenSelectView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/InputCard/TokenSelectView.swift @@ -1,7 +1,7 @@ -import Foundation -import UIKit import ComponentKit +import Foundation import ThemeKit +import UIKit class TokenSelectView: UIView { let wrapperButton = UIButton() @@ -9,7 +9,7 @@ class TokenSelectView: UIView { let tokenButton = SecondaryButton() - var onTap: (() -> ())? + var onTap: (() -> Void)? init() { super.init(frame: .zero) @@ -41,12 +41,12 @@ class TokenSelectView: UIView { tokenButton.setContentCompressionResistancePriority(.required, for: .horizontal) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func onTapButton() { onTap?() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/PriceView/SwapPriceCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/PriceView/SwapPriceCell.swift index 56a9352cc3..0c02c295d6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/PriceView/SwapPriceCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapNew/PriceView/SwapPriceCell.swift @@ -1,7 +1,7 @@ -import Foundation -import UIKit import ComponentKit +import Foundation import HUD +import UIKit class SwapPriceCell: BaseThemeCell { private static let buttonHeight: CGFloat = 28 @@ -9,18 +9,18 @@ class SwapPriceCell: BaseThemeCell { let titleLabel = UILabel() let priceButton = UIButton() let progressView = HUDProgressView( - progress: 1, - strokeLineWidth: 2, - radius: 7.5, - strokeColor: .themeJacob, - donutColor: .themeSteel20, - duration: 10 + progress: 1, + strokeLineWidth: 2, + radius: 7.5, + strokeColor: .themeJacob, + donutColor: .themeSteel20, + duration: 10 ) private var isReverted = false private var viewItem: PriceViewItem? - override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style _: UITableViewCell.CellStyle, reuseIdentifier _: String?) { super.init(style: .default, reuseIdentifier: nil) backgroundColor = .clear @@ -66,7 +66,8 @@ class SwapPriceCell: BaseThemeCell { priceButton.setTitleColor(.themeDark, for: [.selected, .highlighted]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -79,11 +80,9 @@ class SwapPriceCell: BaseThemeCell { private func syncPrice() { priceButton.setTitle(isReverted ? viewItem?.revertedPrice : viewItem?.price, for: .normal) } - } extension SwapPriceCell { - func set(item: PriceViewItem?) { viewItem = item @@ -93,14 +92,11 @@ extension SwapPriceCell { func set(progress: Float) { progressView.set(progress: progress) } - } extension SwapPriceCell { - struct PriceViewItem { let price: String? let revertedPrice: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderModule.swift index 8ade3a1bca..d6fb42e685 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderModule.swift @@ -1,8 +1,7 @@ -import UIKit import ThemeKit +import UIKit struct SwapSelectProviderModule { - static func viewController(dexManager: ISwapDexManager) -> UIViewController { let service = SwapSelectProviderService(dexManager: dexManager, evmBlockchainManager: App.shared.evmBlockchainManager) @@ -10,5 +9,4 @@ struct SwapSelectProviderModule { return SwapSelectProviderViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderService.swift index 5b88f25f18..bb0f4973e2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderService.swift @@ -1,7 +1,7 @@ -import RxSwift +import MarketKit import RxRelay +import RxSwift import ThemeKit -import MarketKit class SwapSelectProviderService { private let dexManager: ISwapDexManager @@ -28,18 +28,15 @@ class SwapSelectProviderService { } var items = [Item]() - for provider in dex.blockchainType.allowedProviders { items.append(Item(provider: provider, selected: provider == dex.provider)) } self.items = items } - } extension SwapSelectProviderService { - var itemsObservable: Observable<[Item]> { itemsRelay.asObservable() } @@ -53,14 +50,11 @@ extension SwapSelectProviderService { syncItems() } - } extension SwapSelectProviderService { - struct Item { let provider: SwapModule.Dex.Provider let selected: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewController.swift index 4825909351..8e0ae1d62e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewController.swift @@ -1,8 +1,8 @@ -import UIKit +import ComponentKit +import RxSwift import SectionsTableView import ThemeKit -import RxSwift -import ComponentKit +import UIKit class SwapSelectProviderViewController: ThemeActionSheetController { private let viewModel: SwapSelectProviderViewModel @@ -22,7 +22,8 @@ class SwapSelectProviderViewController: ThemeActionSheetController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -35,9 +36,9 @@ class SwapSelectProviderViewController: ThemeActionSheetController { } titleView.bind( - image: .local(name: "arrow_swap_2_24", tint: .warning), - title: "swap.switch_provider.title".localized, - viewController: self + image: .local(name: "arrow_swap_2_24", tint: .warning), + title: "swap.switch_provider.title".localized, + viewController: self ) view.addSubview(tableView) @@ -72,33 +73,30 @@ class SwapSelectProviderViewController: ThemeActionSheetController { tableView.reload(animated: true) } - } extension SwapSelectProviderViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "theme", - rows: viewItems.enumerated().map { index, viewItem in - tableView.universalRow56( - id: viewItem.title, - image: .local(UIImage(named: viewItem.icon)), - title: .body(viewItem.title), - accessoryType: .check(viewItem.selected), - hash: viewItem.selected.description, - backgroundStyle: .bordered, - isFirst: index == 0, - isLast: index == viewItems.count - 1, - action: { [weak self] in - self?.viewModel.onSelect(index: index) - self?.dismiss(animated: true) - } - ) - } - ) + id: "theme", + rows: viewItems.enumerated().map { index, viewItem in + tableView.universalRow56( + id: viewItem.title, + image: .local(UIImage(named: viewItem.icon)), + title: .body(viewItem.title), + accessoryType: .check(viewItem.selected), + hash: viewItem.selected.description, + backgroundStyle: .bordered, + isFirst: index == 0, + isLast: index == viewItems.count - 1, + action: { [weak self] in + self?.viewModel.onSelect(index: index) + self?.dismiss(animated: true) + } + ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewModel.swift index cc04c543f7..ed116d9e85 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSelectProvider/SwapSelectProviderViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class SwapSelectProviderViewModel { private let service: SwapSelectProviderService @@ -15,11 +15,11 @@ class SwapSelectProviderViewModel { self.service = service service.itemsObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] items in - self?.sync(items: items) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] items in + self?.sync(items: items) + }) + .disposed(by: disposeBag) sync(items: service.items) } @@ -27,19 +27,17 @@ class SwapSelectProviderViewModel { private func sync(items: [SwapSelectProviderService.Item]) { let viewItems = items.map { item in ViewItem( - title: item.provider.rawValue, - icon: item.provider.icon, - selected: item.selected + title: item.provider.rawValue, + icon: item.provider.icon, + selected: item.selected ) } sectionViewItemsRelay.accept(viewItems) } - } extension SwapSelectProviderViewModel { - var selectedSignal: Signal { selectedRelay.asSignal() } @@ -56,15 +54,12 @@ extension SwapSelectProviderViewModel { service.set(provider: service.items[index].provider) selectedRelay.accept(()) } - } extension SwapSelectProviderViewModel { - struct ViewItem { let title: String let icon: String let selected: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettings.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettings.swift index d7207648e2..ea686dd1c6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettings.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettings.swift @@ -1,6 +1,6 @@ +import EvmKit import Foundation import UniswapKit -import EvmKit struct OneInchSettings { var allowedSlippage: Decimal @@ -10,5 +10,4 @@ struct OneInchSettings { self.allowedSlippage = allowedSlippage self.recipient = recipient } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsDataSource.swift index 54befd9547..b172cc0dd1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsDataSource.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import RxSwift +import ComponentKit import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import ThemeKit +import UIKit class OneInchSettingsDataSource: ISwapSettingsDataSource { private let disposeBag = DisposeBag() @@ -19,10 +19,10 @@ class OneInchSettingsDataSource: ISwapSettingsDataSource { private let serviceFeeNoteCell = HighlightedDescriptionCell(showVerticalMargin: false) - var onOpen: ((UIViewController) -> ())? - var onClose: (() -> ())? - var onReload: (() -> ())? - var onChangeButtonState: ((Bool, String) -> ())? + var onOpen: ((UIViewController) -> Void)? + var onClose: (() -> Void)? + var onReload: (() -> Void)? + var onChangeButtonState: ((Bool, String) -> Void)? init(viewModel: OneInchSettingsViewModel, recipientViewModel: RecipientAddressViewModel, slippageViewModel: SwapSlippageViewModel) { self.viewModel = viewModel @@ -32,7 +32,8 @@ class OneInchSettingsDataSource: ISwapSettingsDataSource { recipientCautionCell = RecipientAddressCautionCell(viewModel: recipientViewModel) } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -63,7 +64,7 @@ class OneInchSettingsDataSource: ISwapSettingsDataSource { switch actionState { case .enabled: self?.onChangeButtonState?(true, "button.apply".localized) - case .disabled(let title): + case let .disabled(title): self?.onChangeButtonState?(false, title) } } @@ -76,76 +77,73 @@ class OneInchSettingsDataSource: ISwapSettingsDataSource { HudHelper.instance.show(banner: .error(string: "alert.unknown_error".localized)) } } - } extension OneInchSettingsDataSource { - func buildSections(tableView: SectionsTableView) -> [SectionProtocol] { [ Section( - id: "top-margin", - headerState: .margin(height: .margin12) + id: "top-margin", + headerState: .margin(height: .margin12) ), Section( - id: "recipient", - headerState: tableView.sectionHeader(text: "swap.advanced_settings.recipient_address".localized), - footerState: tableView.sectionFooter(text: "swap.advanced_settings.recipient.footer".localized), - rows: [ - StaticRow( - cell: recipientCell, - id: "recipient-input", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "recipient-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "recipient", + headerState: tableView.sectionHeader(text: "swap.advanced_settings.recipient_address".localized), + footerState: tableView.sectionFooter(text: "swap.advanced_settings.recipient.footer".localized), + rows: [ + StaticRow( + cell: recipientCell, + id: "recipient-input", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: recipientCautionCell, + id: "recipient-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "slippage", - headerState: tableView.sectionHeader(text: "swap.advanced_settings.slippage".localized), - footerState: tableView.sectionFooter(text: "swap.advanced_settings.slippage.footer".localized), - rows: [ - StaticRow( - cell: slippageCell, - id: "slippage", - dynamicHeight: { [weak self] width in - self?.slippageCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: slippageCautionCell, - id: "slippage-caution", - dynamicHeight: { [weak self] width in - self?.slippageCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "slippage", + headerState: tableView.sectionHeader(text: "swap.advanced_settings.slippage".localized), + footerState: tableView.sectionFooter(text: "swap.advanced_settings.slippage.footer".localized), + rows: [ + StaticRow( + cell: slippageCell, + id: "slippage", + dynamicHeight: { [weak self] width in + self?.slippageCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: slippageCautionCell, + id: "slippage-caution", + dynamicHeight: { [weak self] width in + self?.slippageCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "service-fee", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: serviceFeeNoteCell, - id: "service-fee-cell", - dynamicHeight: { [weak self] width in - self?.serviceFeeNoteCell.height(containerWidth: width) ?? 0 - } - ) - ] - ) + id: "service-fee", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: serviceFeeNoteCell, + id: "service-fee-cell", + dynamicHeight: { [weak self] width in + self?.serviceFeeNoteCell.height(containerWidth: width) ?? 0 + } + ), + ] + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsModule.swift index c7f0a55693..3ff15832aa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsModule.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit struct OneInchSettingsModule { - static func dataSource(tradeService: OneInchTradeService) -> ISwapSettingsDataSource? { guard let ethereumToken = try? App.shared.marketKit.token(query: TokenQuery(blockchainType: .ethereum, tokenType: .native)) else { return nil @@ -17,11 +16,12 @@ struct OneInchSettingsModule { let udnAddressParserItem = UdnAddressParserItem.item(rawAddressParserItem: evmAddressParserItem, coinCode: coinCode, token: token) let addressParserChain = AddressParserChain() - .append(handler: evmAddressParserItem) - .append(handler: udnAddressParserItem) + .append(handler: evmAddressParserItem) + .append(handler: udnAddressParserItem) if let httpSyncSource = App.shared.evmSyncSourceManager.httpSyncSource(blockchainType: .ethereum), - let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) { + let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) + { addressParserChain.append(handler: ensAddressParserItem) } @@ -35,10 +35,9 @@ struct OneInchSettingsModule { let slippageViewModel = SwapSlippageViewModel(service: service, decimalParser: AmountDecimalParser()) return OneInchSettingsDataSource( - viewModel: viewModel, - recipientViewModel: recipientViewModel, - slippageViewModel: slippageViewModel + viewModel: viewModel, + recipientViewModel: recipientViewModel, + slippageViewModel: slippageViewModel ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsService.swift index a4fa19348e..5dd8e9bb8a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsService.swift @@ -1,13 +1,13 @@ -import Foundation -import UniswapKit import EvmKit +import Foundation import RxCocoa import RxSwift +import UniswapKit class OneInchSettingsService { static let defaultSlippage: Decimal = 1 var recommendedSlippages: [Decimal] = [0.1, 3] - private var limitSlippageBounds: ClosedRange { 0.01...50 } + private var limitSlippageBounds: ClosedRange { 0.01 ... 50 } private var usualHighestSlippage: Decimal = 5 private let disposeBag = DisposeBag() @@ -18,6 +18,7 @@ class OneInchSettingsService { errorsRelay.accept(errors) } } + private let errorsRelay = PublishRelay<[Error]>() private let slippageChangeRelay = PublishRelay() @@ -54,7 +55,7 @@ class OneInchSettingsService { switch addressService.state { case .loading: loading = true - case .success(let address): settings.recipient = address + case let .success(address): settings.recipient = address case .validationError: errors.append(SwapSettingsModule.AddressError.invalidAddress) case .fetchError: errors.append(SwapSettingsModule.AddressError.invalidAddress) default: () @@ -74,11 +75,9 @@ class OneInchSettingsService { state = (!errors.isEmpty || loading) ? .invalid : .valid(settings) } - } extension OneInchSettingsService { - var errorsObservable: Observable<[Error]> { errorsRelay.asObservable() } @@ -86,11 +85,9 @@ extension OneInchSettingsService { var stateObservable: Observable { stateRelay.asObservable() } - } extension OneInchSettingsService: ISlippageService { - private func visibleSlippageError(errors: [Error]) -> Error? { errors.first { if let error = $0 as? SwapSettingsModule.SlippageError { @@ -130,14 +127,11 @@ extension OneInchSettingsService: ISlippageService { func set(slippage: Decimal) { self.slippage = slippage } - } extension OneInchSettingsService { - enum State { case valid(OneInchSettings) case invalid } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsViewModel.swift index 1611766a93..3a23de6a96 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/OneInchSettings/OneInchSettingsViewModel.swift @@ -1,5 +1,5 @@ -import RxSwift import RxCocoa +import RxSwift class OneInchSettingsViewModel { private let disposeBag = DisposeBag() @@ -14,11 +14,11 @@ class OneInchSettingsViewModel { self.tradeService = tradeService service.stateObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] _ in - self?.syncAction() - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] _ in + self?.syncAction() + }) + .disposed(by: disposeBag) } private func syncAction() { @@ -39,11 +39,9 @@ class OneInchSettingsViewModel { } } } - } extension OneInchSettingsViewModel { - public var actionDriver: Driver { actionRelay.asDriver() } @@ -55,14 +53,11 @@ extension OneInchSettingsViewModel { } return false } - } extension OneInchSettingsViewModel { - enum ActionState { case enabled case disabled(title: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsModule.swift index ebde26c216..00736e4b19 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsModule.swift @@ -1,30 +1,27 @@ -import UIKit import EvmKit import SectionsTableView import ThemeKit +import UIKit protocol ISwapSettingsDataSource: AnyObject { func viewDidLoad() func buildSections(tableView: SectionsTableView) -> [SectionProtocol] func didTapApply() - var onOpen: ((UIViewController) -> ())? { get set } - var onClose: (() -> ())? { get set } - var onReload: (() -> ())? { get set } - var onChangeButtonState: ((Bool, String) -> ())? { get set } + var onOpen: ((UIViewController) -> Void)? { get set } + var onClose: (() -> Void)? { get set } + var onReload: (() -> Void)? { get set } + var onChangeButtonState: ((Bool, String) -> Void)? { get set } } -class SwapSettingsModule { - - static func viewController(dataSourceManager: ISwapDataSourceManager, dexManager: ISwapDexManager) -> UIViewController? { +enum SwapSettingsModule { + static func viewController(dataSourceManager: ISwapDataSourceManager, dexManager _: ISwapDexManager) -> UIViewController? { let viewController = SwapSettingsViewController(dataSourceManager: dataSourceManager) return ThemeNavigationController(rootViewController: viewController) } - } extension SwapSettingsModule { - enum AddressError: Error { case invalidAddress } @@ -38,5 +35,4 @@ extension SwapSettingsModule { enum DeadlineError: Error { case zeroValue } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsViewController.swift index 9e00dba397..a57b7e0caf 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/SwapSettingsViewController.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit -import UniswapKit +import ComponentKit import HUD -import RxSwift import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import ThemeKit import UIExtensions +import UIKit +import UniswapKit class SwapSettingsViewController: KeyboardAwareViewController { private let animationDuration: TimeInterval = 0.2 @@ -31,7 +31,8 @@ class SwapSettingsViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -104,19 +105,16 @@ class SwapSettingsViewController: KeyboardAwareViewController { self.tableView.endUpdates() } } - } extension SwapSettingsViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [SectionProtocol]() - if let dataSource = dataSource { + if let dataSource { sections.append(contentsOf: dataSource.buildSections(tableView: tableView)) } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettings.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettings.swift index 882e02185d..66dc872b8b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettings.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettings.swift @@ -1,6 +1,6 @@ +import EvmKit import Foundation import UniswapKit -import EvmKit struct UniswapSettings { var allowedSlippage: Decimal @@ -15,10 +15,9 @@ struct UniswapSettings { var tradeOptions: TradeOptions { TradeOptions( - allowedSlippage: allowedSlippage, - ttl: ttl, - recipient: recipient.flatMap { try? EvmKit.Address(hex: $0.raw) } + allowedSlippage: allowedSlippage, + ttl: ttl, + recipient: recipient.flatMap { try? EvmKit.Address(hex: $0.raw) } ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsDataSource.swift index 9e01fca2c2..1d32a1f640 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsDataSource.swift @@ -1,9 +1,9 @@ -import UIKit -import ThemeKit -import RxSwift +import ComponentKit import RxCocoa +import RxSwift import SectionsTableView -import ComponentKit +import ThemeKit +import UIKit class UniswapSettingsDataSource: ISwapSettingsDataSource { private let disposeBag = DisposeBag() @@ -22,10 +22,10 @@ class UniswapSettingsDataSource: ISwapSettingsDataSource { private let serviceFeeNoteCell = HighlightedDescriptionCell(showVerticalMargin: false) - var onOpen: ((UIViewController) -> ())? - var onClose: (() -> ())? - var onReload: (() -> ())? - var onChangeButtonState: ((Bool, String) -> ())? + var onOpen: ((UIViewController) -> Void)? + var onClose: (() -> Void)? + var onReload: (() -> Void)? + var onChangeButtonState: ((Bool, String) -> Void)? init(viewModel: UniswapSettingsViewModel, recipientViewModel: RecipientAddressViewModel, slippageViewModel: SwapSlippageViewModel, deadlineViewModel: SwapDeadlineViewModel?) { self.viewModel = viewModel @@ -36,7 +36,8 @@ class UniswapSettingsDataSource: ISwapSettingsDataSource { recipientCautionCell = RecipientAddressCautionCell(viewModel: recipientViewModel) } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -82,7 +83,7 @@ class UniswapSettingsDataSource: ISwapSettingsDataSource { switch actionState { case .enabled: self?.onChangeButtonState?(true, "button.apply".localized) - case .disabled(let title): + case let .disabled(title): self?.onChangeButtonState?(false, title) } } @@ -95,92 +96,89 @@ class UniswapSettingsDataSource: ISwapSettingsDataSource { HudHelper.instance.show(banner: .error(string: "alert.unknown_error".localized)) } } - } extension UniswapSettingsDataSource { - func buildSections(tableView: SectionsTableView) -> [SectionProtocol] { var sections = [ Section( - id: "top-margin", - headerState: .margin(height: .margin12) + id: "top-margin", + headerState: .margin(height: .margin12) ), Section( - id: "recipient", - headerState: tableView.sectionHeader(text: "swap.advanced_settings.recipient_address".localized), - footerState: tableView.sectionFooter(text: "swap.advanced_settings.recipient.footer".localized), - rows: [ - StaticRow( - cell: recipientCell, - id: "recipient-input", - dynamicHeight: { [weak self] width in - self?.recipientCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: recipientCautionCell, - id: "recipient-caution", - dynamicHeight: { [weak self] width in - self?.recipientCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "recipient", + headerState: tableView.sectionHeader(text: "swap.advanced_settings.recipient_address".localized), + footerState: tableView.sectionFooter(text: "swap.advanced_settings.recipient.footer".localized), + rows: [ + StaticRow( + cell: recipientCell, + id: "recipient-input", + dynamicHeight: { [weak self] width in + self?.recipientCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: recipientCautionCell, + id: "recipient-caution", + dynamicHeight: { [weak self] width in + self?.recipientCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), Section( - id: "slippage", - headerState: tableView.sectionHeader(text: "swap.advanced_settings.slippage".localized), - footerState: tableView.sectionFooter(text: "swap.advanced_settings.slippage.footer".localized), - rows: [ - StaticRow( - cell: slippageCell, - id: "slippage", - dynamicHeight: { [weak self] width in - self?.slippageCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: slippageCautionCell, - id: "slippage-caution", - dynamicHeight: { [weak self] width in - self?.slippageCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "slippage", + headerState: tableView.sectionHeader(text: "swap.advanced_settings.slippage".localized), + footerState: tableView.sectionFooter(text: "swap.advanced_settings.slippage.footer".localized), + rows: [ + StaticRow( + cell: slippageCell, + id: "slippage", + dynamicHeight: { [weak self] width in + self?.slippageCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: slippageCautionCell, + id: "slippage-caution", + dynamicHeight: { [weak self] width in + self?.slippageCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ), ] if deadlineViewModel != nil { sections.append(Section( - id: "deadline", - headerState: tableView.sectionHeader(text: "swap.advanced_settings.deadline".localized), - footerState: tableView.sectionFooter(text: "swap.advanced_settings.deadline.footer".localized), - rows: [ - StaticRow( - cell: deadlineCell, - id: "deadline", - dynamicHeight: { [weak self] width in - self?.deadlineCell.height(containerWidth: width) ?? 0 - } - ) - ] - )) - } - sections.append(Section( - id: "service-fee", + id: "deadline", + headerState: tableView.sectionHeader(text: "swap.advanced_settings.deadline".localized), + footerState: tableView.sectionFooter(text: "swap.advanced_settings.deadline.footer".localized), rows: [ StaticRow( - cell: serviceFeeNoteCell, - id: "service-fee-cell", - dynamicHeight: { [weak self] width in - self?.serviceFeeNoteCell.height(containerWidth: width) ?? 0 - } - ) + cell: deadlineCell, + id: "deadline", + dynamicHeight: { [weak self] width in + self?.deadlineCell.height(containerWidth: width) ?? 0 + } + ), ] - ) + )) + } + sections.append(Section( + id: "service-fee", + rows: [ + StaticRow( + cell: serviceFeeNoteCell, + id: "service-fee-cell", + dynamicHeight: { [weak self] width in + self?.serviceFeeNoteCell.height(containerWidth: width) ?? 0 + } + ), + ] + ) ) return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsModule.swift index ee09336c23..d8fc196a58 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsModule.swift @@ -1,14 +1,13 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit protocol ISwapSettingProvider: AnyObject { var tokenIn: Token? { get } var settings: UniswapSettings { get set } } -struct UniswapSettingsModule { - +enum UniswapSettingsModule { static func dataSource(settingProvider: ISwapSettingProvider, showDeadline: Bool) -> ISwapSettingsDataSource? { guard let ethereumToken = try? App.shared.marketKit.token(query: TokenQuery(blockchainType: .ethereum, tokenType: .native)) else { return nil @@ -21,11 +20,12 @@ struct UniswapSettingsModule { let evmAddressParserItem = EvmAddressParser() let udnAddressParserItem = UdnAddressParserItem.item(rawAddressParserItem: evmAddressParserItem, coinCode: coinCode, token: token) let addressParserChain = AddressParserChain() - .append(handler: evmAddressParserItem) - .append(handler: udnAddressParserItem) + .append(handler: evmAddressParserItem) + .append(handler: udnAddressParserItem) if let httpSyncSource = App.shared.evmSyncSourceManager.httpSyncSource(blockchainType: .ethereum), - let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) { + let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) + { addressParserChain.append(handler: ensAddressParserItem) } @@ -39,16 +39,14 @@ struct UniswapSettingsModule { let slippageViewModel = SwapSlippageViewModel(service: service, decimalParser: AmountDecimalParser()) let deadlineViewModel: SwapDeadlineViewModel? = showDeadline ? - .init(service: service, decimalParser: AmountDecimalParser()) : - nil + .init(service: service, decimalParser: AmountDecimalParser()) : + nil return UniswapSettingsDataSource( - viewModel: viewModel, - recipientViewModel: recipientViewModel, - slippageViewModel: slippageViewModel, - deadlineViewModel: deadlineViewModel + viewModel: viewModel, + recipientViewModel: recipientViewModel, + slippageViewModel: slippageViewModel, + deadlineViewModel: deadlineViewModel ) } - } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsService.swift index 297d49ad86..f059ac3061 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsService.swift @@ -1,15 +1,15 @@ -import Foundation -import UniswapKit import EvmKit +import Foundation import RxCocoa import RxSwift +import UniswapKit class UniswapSettingsService { var recommendedSlippages: [Decimal] = [0.1, 1] - private var limitSlippageBounds: ClosedRange { 0.01...50 } + private var limitSlippageBounds: ClosedRange { 0.01 ... 50 } private var usualHighestSlippage: Decimal = 5 - var recommendedDeadlineBounds: ClosedRange { 600...1800 } + var recommendedDeadlineBounds: ClosedRange { 600 ... 1800 } private let disposeBag = DisposeBag() private let addressService: AddressService @@ -19,6 +19,7 @@ class UniswapSettingsService { errorsRelay.accept(errors) } } + private let errorsRelay = PublishRelay<[Error]>() private let slippageChangeRelay = PublishRelay() @@ -62,7 +63,7 @@ class UniswapSettingsService { switch addressService.state { case .loading: loading = true - case .success(let address): settings.recipient = address + case let .success(address): settings.recipient = address case .validationError: errors.append(SwapSettingsModule.AddressError.invalidAddress) case .fetchError: errors.append(SwapSettingsModule.AddressError.invalidAddress) default: () @@ -88,11 +89,9 @@ class UniswapSettingsService { state = (!errors.isEmpty || loading) ? .invalid : .valid(settings) } - } extension UniswapSettingsService { - var errorsObservable: Observable<[Error]> { errorsRelay.asObservable() } @@ -100,11 +99,9 @@ extension UniswapSettingsService { var stateObservable: Observable { stateRelay.asObservable() } - } extension UniswapSettingsService: ISlippageService { - private func visibleSlippageError(errors: [Error]) -> Error? { errors.first { if let error = $0 as? SwapSettingsModule.SlippageError { @@ -144,14 +141,11 @@ extension UniswapSettingsService: ISlippageService { func set(slippage: Decimal) { self.slippage = slippage } - } extension UniswapSettingsService { - enum State { case valid(UniswapSettings) case invalid } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsViewModel.swift index beac72ab78..07d99ce34c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/UniswapSettings/UniswapSettingsViewModel.swift @@ -1,5 +1,5 @@ -import RxSwift import RxCocoa +import RxSwift class UniswapSettingsViewModel { private let disposeBag = DisposeBag() @@ -14,11 +14,11 @@ class UniswapSettingsViewModel { self.settingProvider = settingProvider service.stateObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] _ in - self?.syncAction() - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] _ in + self?.syncAction() + }) + .disposed(by: disposeBag) } private func syncAction() { @@ -41,11 +41,9 @@ class UniswapSettingsViewModel { } } } - } extension UniswapSettingsViewModel { - public var actionDriver: Driver { actionRelay.asDriver() } @@ -57,14 +55,11 @@ extension UniswapSettingsViewModel { } return false } - } extension UniswapSettingsViewModel { - enum ActionState { case enabled case disabled(title: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/AddressResolutionProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/AddressResolutionProvider.swift index ebc72f8dea..c41c24255a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/AddressResolutionProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/AddressResolutionProvider.swift @@ -12,8 +12,8 @@ class AddressResolutionProvider { Single.create { [weak self] observer in self?.resolution?.isSupported(domain: domain) { result in switch result { - case .success(let valid): observer(.success(valid)) - case .failure(let error): observer(.error(error)) + case let .success(valid): observer(.success(valid)) + case let .failure(error): observer(.error(error)) } } @@ -25,13 +25,13 @@ class AddressResolutionProvider { Single>.create { [weak self] observer in let completionBlock: StringResultConsumer = { result in switch result { - case .success(let returnValue): + case let .success(returnValue): observer(.success(.success(returnValue))) - case .failure(let error): + case let .failure(error): observer(.success(.failure(error))) } } - if let chain = chain { + if let chain { self?.resolution?.multiChainAddress(domain: domain, ticker: ticker, chain: chain, completion: completionBlock) } else { self?.resolution?.addr(domain: domain, ticker: ticker, completion: completionBlock) @@ -40,5 +40,4 @@ class AddressResolutionProvider { return Disposables.create() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapDeadlineViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapDeadlineViewModel.swift index 70421b9e1d..b772dcb6fd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapDeadlineViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapDeadlineViewModel.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxCocoa +import RxSwift import UniswapKit class SwapDeadlineViewModel { @@ -17,11 +17,9 @@ class SwapDeadlineViewModel { private func toString(_ value: Double) -> String { Decimal(floatLiteral: floor(value / 60)).description } - } extension SwapDeadlineViewModel { - var placeholder: String { toString(TradeOptions.defaultTtl) } @@ -59,5 +57,4 @@ extension SwapDeadlineViewModel { return amount.decimalCount == 0 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapSlippageViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapSlippageViewModel.swift index 725c89cead..df289e95d2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapSlippageViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwapSettings/ViewModels/SwapSlippageViewModel.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxCocoa +import RxSwift import UniswapKit protocol ISlippageService { @@ -28,11 +28,11 @@ class SwapSlippageViewModel { self.decimalParser = decimalParser service.slippageChangeObservable - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) - .subscribe(onNext: { [weak self] in - self?.sync() - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) + .subscribe(onNext: { [weak self] in + self?.sync() + }) + .disposed(by: disposeBag) sync() } @@ -50,11 +50,9 @@ class SwapSlippageViewModel { cautionRelay.accept(caution) } - } extension SwapSlippageViewModel { - var placeholder: String { service.defaultSlippage.description } @@ -89,17 +87,14 @@ extension SwapSlippageViewModel { return amount.decimalCount <= 2 } - } extension SwapSettingsModule.SlippageError: LocalizedError { - var errorDescription: String? { switch self { case .tooLow: return "swap.advanced_settings.error.lower_slippage".localized - case .tooHigh(let max): return "swap.advanced_settings.error.higher_slippage".localized(max.description) + case let .tooHigh(max): return "swap.advanced_settings.error.higher_slippage".localized(max.description) default: return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountModule.swift index b449ee48d5..aaba29c3f7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountModule.swift @@ -1,11 +1,9 @@ import UIKit struct SwitchAccountModule { - static func viewController() -> UIViewController { let service = SwitchAccountService(accountManager: App.shared.accountManager) let viewModel = SwitchAccountViewModel(service: service) return SwitchAccountViewController(viewModel: viewModel).toBottomSheet } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountService.swift index 65733968f4..284fed76e4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountService.swift @@ -4,11 +4,9 @@ class SwitchAccountService { init(accountManager: AccountManager) { self.accountManager = accountManager } - } extension SwitchAccountService { - var items: [Item] { let activeAccount = accountManager.activeAccount return accountManager.accounts.map { account in @@ -19,14 +17,11 @@ extension SwitchAccountService { func set(activeAccountId: String) { accountManager.set(activeAccountId: activeAccountId) } - } extension SwitchAccountService { - struct Item { let account: Account let isActive: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewController.swift index 4f977c7a22..5c9c538aef 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewController.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit +import ComponentKit +import RxCocoa +import RxSwift import SectionsTableView import SnapKit -import RxSwift -import RxCocoa -import ComponentKit +import ThemeKit +import UIKit class SwitchAccountViewController: ThemeActionSheetController { private let viewModel: SwitchAccountViewModel @@ -18,7 +18,8 @@ class SwitchAccountViewController: ThemeActionSheetController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -31,9 +32,9 @@ class SwitchAccountViewController: ThemeActionSheetController { } titleView.bind( - image: .local(name: "switch_wallet_24", tint: .warning), - title: "switch_account.title".localized, - viewController: self + image: .local(name: "switch_wallet_24", tint: .warning), + title: "switch_account.title".localized, + viewController: self ) view.addSubview(tableView) @@ -50,44 +51,42 @@ class SwitchAccountViewController: ThemeActionSheetController { subscribe(disposeBag, viewModel.finishSignal) { [weak self] in self?.dismiss(animated: true) } } - } extension SwitchAccountViewController: SectionsDataSource { - private func row(viewItem: SwitchAccountViewModel.ViewItem, watchIcon: Bool, index: Int, isFirst: Bool, isLast: Bool) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .image24 { component in - component.imageView.image = viewItem.selected ? UIImage(named: "circle_radioon_24")?.withTintColor(.themeJacob) : UIImage(named: "circle_radiooff_24")?.withTintColor(.themeGray) + rootElement: .hStack([ + .image24 { component in + component.imageView.image = viewItem.selected ? UIImage(named: "circle_radioon_24")?.withTintColor(.themeJacob) : UIImage(named: "circle_radiooff_24")?.withTintColor(.themeGray) + }, + .vStackCentered([ + .text { component in + component.font = .body + component.textColor = .themeLeah + component.text = viewItem.title + }, + .margin(1), + .text { component in + component.font = .subhead2 + component.textColor = .themeGray + component.text = viewItem.subtitle }, - .vStackCentered([ - .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = viewItem.title - }, - .margin(1), - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = viewItem.subtitle - } - ]), - .image20 { component in - component.isHidden = !watchIcon - component.imageView.image = UIImage(named: "binocule_20")?.withTintColor(.themeGray) - } ]), - tableView: tableView, - id: "item_\(index)", - height: .heightDoubleLineCell, - bind: { cell in - cell.set(backgroundStyle: .bordered, isFirst: isFirst, isLast: isLast) + .image20 { component in + component.isHidden = !watchIcon + component.imageView.image = UIImage(named: "binocule_20")?.withTintColor(.themeGray) }, - action: { [weak self] in - self?.viewModel.onSelect(accountId: viewItem.accountId) - } + ]), + tableView: tableView, + id: "item_\(index)", + height: .heightDoubleLineCell, + bind: { cell in + cell.set(backgroundStyle: .bordered, isFirst: isFirst, isLast: isLast) + }, + action: { [weak self] in + self?.viewModel.onSelect(accountId: viewItem.accountId) + } ) } @@ -96,12 +95,12 @@ extension SwitchAccountViewController: SectionsDataSource { if !viewModel.regularViewItems.isEmpty { let section = Section( - id: "regular", - headerState: tableView.sectionHeader(text: "switch_account.wallets".localized, backgroundColor: .themeLawrence), - footerState: .marginColor(height: .margin24, color: .clear), - rows: viewModel.regularViewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, watchIcon: false, index: index, isFirst: index == 0, isLast: index == viewModel.regularViewItems.count - 1) - } + id: "regular", + headerState: tableView.sectionHeader(text: "switch_account.wallets".localized, backgroundColor: .themeLawrence), + footerState: .marginColor(height: .margin24, color: .clear), + rows: viewModel.regularViewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, watchIcon: false, index: index, isFirst: index == 0, isLast: index == viewModel.regularViewItems.count - 1) + } ) sections.append(section) @@ -109,12 +108,12 @@ extension SwitchAccountViewController: SectionsDataSource { if !viewModel.watchViewItems.isEmpty { let section = Section( - id: "watch", - headerState: tableView.sectionHeader(text: "switch_account.watch_wallets".localized, backgroundColor: .themeLawrence), - footerState: .marginColor(height: .margin24, color: .clear), - rows: viewModel.watchViewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, watchIcon: true, index: index, isFirst: index == 0, isLast: index == viewModel.watchViewItems.count - 1) - } + id: "watch", + headerState: tableView.sectionHeader(text: "switch_account.watch_wallets".localized, backgroundColor: .themeLawrence), + footerState: .marginColor(height: .margin24, color: .clear), + rows: viewModel.watchViewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, watchIcon: true, index: index, isFirst: index == 0, isLast: index == viewModel.watchViewItems.count - 1) + } ) sections.append(section) @@ -122,5 +121,4 @@ extension SwitchAccountViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewModel.swift index 0c3f304227..6442ca1560 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/SwitchAccount/SwitchAccountViewModel.swift @@ -1,13 +1,13 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class SwitchAccountViewModel { private let service: SwitchAccountService private(set) var regularViewItems = [ViewItem]() private(set) var watchViewItems = [ViewItem]() - private let finishRelay = PublishRelay<()>() + private let finishRelay = PublishRelay() init(service: SwitchAccountService) { self.service = service @@ -15,23 +15,21 @@ class SwitchAccountViewModel { let sortedItems = service.items.sorted { $0.account.name.lowercased() < $1.account.name.lowercased() } regularViewItems = sortedItems.filter { !$0.account.watchAccount }.map { viewItem(item: $0) } - watchViewItems = sortedItems.filter { $0.account.watchAccount }.map { viewItem(item: $0) } + watchViewItems = sortedItems.filter(\.account.watchAccount).map { viewItem(item: $0) } } private func viewItem(item: SwitchAccountService.Item) -> ViewItem { ViewItem( - accountId: item.account.id, - title: item.account.name, - subtitle: item.account.type.detailedDescription, - selected: item.isActive + accountId: item.account.id, + title: item.account.name, + subtitle: item.account.type.detailedDescription, + selected: item.isActive ) } - } extension SwitchAccountViewModel { - - var finishSignal: Signal<()> { + var finishSignal: Signal { finishRelay.asSignal() } @@ -39,16 +37,13 @@ extension SwitchAccountViewModel { service.set(activeAccountId: accountId) finishRelay.accept(()) } - } extension SwitchAccountViewModel { - struct ViewItem { let accountId: String let title: String let subtitle: String let selected: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoModule.swift index 965b3a62d1..2bacd68331 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoModule.swift @@ -1,8 +1,7 @@ -import UIKit import MarketKit +import UIKit struct TransactionInfoModule { - static func instance(transactionRecord: TransactionRecord) -> UIViewController? { guard let adapter = App.shared.transactionAdapterManager.adapter(for: transactionRecord.source) else { return nil @@ -18,11 +17,9 @@ struct TransactionInfoModule { return viewController } - } extension TransactionInfoModule { - enum Option { case resend(type: ResendEvmTransactionType) } @@ -52,5 +49,4 @@ extension TransactionInfoModule { case explorer(title: String, url: String?) case warning(text: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoService.swift index 4be33aa814..73e97aa2e3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoService.swift @@ -50,22 +50,22 @@ class TransactionInfoService { case let tx as ApproveTransactionRecord: tokens.append(tx.value.token) case let tx as ContractCallTransactionRecord: - tokens.append(contentsOf: tx.incomingEvents.map { $0.value.token }) - tokens.append(contentsOf: tx.outgoingEvents.map { $0.value.token }) + tokens.append(contentsOf: tx.incomingEvents.map(\.value.token)) + tokens.append(contentsOf: tx.outgoingEvents.map(\.value.token)) case let tx as ExternalContractCallTransactionRecord: - tokens.append(contentsOf: tx.incomingEvents.map { $0.value.token }) - tokens.append(contentsOf: tx.outgoingEvents.map { $0.value.token }) + tokens.append(contentsOf: tx.incomingEvents.map(\.value.token)) + tokens.append(contentsOf: tx.outgoingEvents.map(\.value.token)) case let tx as TronIncomingTransactionRecord: tokens.append(tx.value.token) case let tx as TronOutgoingTransactionRecord: tokens.append(tx.value.token) case let tx as TronApproveTransactionRecord: tokens.append(tx.value.token) case let tx as TronContractCallTransactionRecord: - tokens.append(contentsOf: tx.incomingEvents.map { $0.value.token }) - tokens.append(contentsOf: tx.outgoingEvents.map { $0.value.token }) + tokens.append(contentsOf: tx.incomingEvents.map(\.value.token)) + tokens.append(contentsOf: tx.outgoingEvents.map(\.value.token)) case let tx as TronExternalContractCallTransactionRecord: - tokens.append(contentsOf: tx.incomingEvents.map { $0.value.token }) - tokens.append(contentsOf: tx.outgoingEvents.map { $0.value.token }) + tokens.append(contentsOf: tx.incomingEvents.map(\.value.token)) + tokens.append(contentsOf: tx.outgoingEvents.map(\.value.token)) case let tx as BitcoinIncomingTransactionRecord: tokens.append(tx.value.token) case let tx as BitcoinOutgoingTransactionRecord: diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewController.swift index b2b2c9c2d7..ff5b6303a7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewController.swift @@ -443,7 +443,7 @@ class TransactionInfoViewController: ThemeViewController { isFirst: rowInfo.isFirst, isLast: rowInfo.isLast, action: { [weak self] in - if let url = url { + if let url { self?.urlManager.open(url: url, from: self) } } @@ -466,7 +466,7 @@ class TransactionInfoViewController: ThemeViewController { case let .amount(iconUrl, iconPlaceholderImageName, coinAmount, currencyAmount, type, coinUid): var action: (() -> Void)? - if let coinUid = coinUid { + if let coinUid { action = { [weak self] in self?.openCoin(coinUid: coinUid) } @@ -476,7 +476,7 @@ class TransactionInfoViewController: ThemeViewController { case let .nftAmount(iconUrl, iconPlaceholderImageName, nftAmount, type, providerCollectionUid, nftUid): var onTapOpenNft: (() -> Void)? - if let providerCollectionUid = providerCollectionUid, let nftUid = nftUid { + if let providerCollectionUid, let nftUid { onTapOpenNft = { [weak self] in self?.openNftAsset(providerCollectionUid: providerCollectionUid, nftUid: nftUid) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewItemFactory.swift index 7ce0ecb989..6a79eb51e1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/TransactionInfo/TransactionInfoViewItemFactory.swift @@ -32,7 +32,7 @@ class TransactionInfoViewItemFactory { } else { var currencyValue: CurrencyValue? - if let rate = rate, let value = transactionValue.decimalValue { + if let rate, let value = transactionValue.decimalValue { currencyValue = CurrencyValue(currency: rate.currency, value: rate.value * value) } @@ -65,7 +65,7 @@ class TransactionInfoViewItemFactory { parts.append(formattedCoinValue) } - if let rate = rate, case let .coinValue(_, value) = transactionValue { + if let rate, case let .coinValue(_, value) = transactionValue { if let formattedCurrencyValue = ValueFormatter.instance.formatFull(currency: rate.currency, value: rate.value * value) { parts.append(formattedCurrencyValue) } @@ -90,7 +90,7 @@ class TransactionInfoViewItemFactory { } private func rateString(currencyValue: CurrencyValue?, coinCode: String?) -> String { - guard let currencyValue = currencyValue, let coinCode = coinCode else { + guard let currencyValue, let coinCode else { return "---" } @@ -163,7 +163,7 @@ class TransactionInfoViewItemFactory { rateViewItem = .rate(value: rateString(currencyValue: rate, coinCode: transactionValue.coin?.code)) } - if !burn, let to = to { + if !burn, let to { let contactData = contactLabelService.contactData(for: to) let valueTitle = contactData.name == nil ? evmLabelManager.addressLabel(address: to) : nil toViewItem = .to(value: to, valueTitle: valueTitle, contactAddress: contactData.contactAddress) @@ -230,7 +230,7 @@ class TransactionInfoViewItemFactory { rateViewItem = .rate(value: rateString(currencyValue: rate, coinCode: transactionValue.coin?.code)) } - if !mint, let from = from { + if !mint, let from { let contactData = contactLabelService.contactData(for: from) let valueTitle = contactData.name == nil ? evmLabelManager.addressLabel(address: from) : nil fromViewItem = .from(value: from, valueTitle: valueTitle, contactAddress: contactData.contactAddress) @@ -585,7 +585,7 @@ class TransactionInfoViewItemFactory { ) } - if let feeViewItem = feeViewItem { + if let feeViewItem { transactionViewItems.append(feeViewItem) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/BaseTransactionsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/BaseTransactionsService.swift index b320258a2c..d1eba0357b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/BaseTransactionsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/BaseTransactionsService.swift @@ -154,7 +154,7 @@ class BaseTransactionsService { queue.async { // print("Fetched tx items: \(transactionItems.count): \(transactionItems)") - let nftUids = transactionItems.map { $0.record }.nftUids + let nftUids = transactionItems.map(\.record).nftUids let nftMetadata = self.nftMetadataService.assetsBriefMetadata(nftUids: nftUids) let missingNftUids = nftUids.subtracting(Set(nftMetadata.keys)) @@ -249,7 +249,7 @@ class BaseTransactionsService { } private func currencyValue(record: TransactionRecord, rate: CurrencyValue?) -> CurrencyValue? { - guard let rate = rate, let decimalValue = record.mainValue?.decimalValue else { + guard let rate, let decimalValue = record.mainValue?.decimalValue else { return nil } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/HistoricalRateService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/HistoricalRateService.swift index dbe7601670..dc47c8fd1e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/HistoricalRateService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/HistoricalRateService.swift @@ -1,9 +1,9 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import MarketKit +import Foundation import HsExtensions +import MarketKit +import RxRelay +import RxSwift class HistoricalRateService { private let marketKit: MarketKit.Kit @@ -23,10 +23,10 @@ class HistoricalRateService { currency = currencyManager.baseCurrency currencyManager.$baseCurrency - .sink { [weak self] currency in - self?.handleUpdated(currency: currency) - } - .store(in: &cancellables) + .sink { [weak self] currency in + self?.handleUpdated(currency: currency) + } + .store(in: &cancellables) } private func handleUpdated(currency: Currency) { @@ -53,11 +53,9 @@ class HistoricalRateService { self?.handle(key: key, rate: rate) }.store(in: &tasks) } - } extension HistoricalRateService { - var rateUpdatedObservable: Observable<(RateKey, CurrencyValue)> { rateUpdatedRelay.asObservable() } @@ -78,7 +76,7 @@ extension HistoricalRateService { if let value = marketKit.cachedCoinHistoricalPriceValue(coinUid: key.token.coin.uid, currencyCode: currency.code, timestamp: key.date.timeIntervalSince1970) { let currencyValue = CurrencyValue(currency: currency, value: value) - rates[key] = currencyValue + rates[key] = currencyValue return currencyValue } @@ -97,7 +95,6 @@ extension HistoricalRateService { } } } - } struct RateKey: Hashable { @@ -112,5 +109,4 @@ struct RateKey: Hashable { static func == (lhs: RateKey, rhs: RateKey) -> Bool { lhs.token == rhs.token && lhs.date == rhs.date } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/NftMetadataService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/NftMetadataService.swift index 0628af528a..c2c865c984 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/NftMetadataService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/NftMetadataService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import MarketKit +import RxRelay +import RxSwift class NftMetadataService { private let nftMetadataManager: NftMetadataManager @@ -19,11 +19,9 @@ class NftMetadataService { let map = Dictionary(uniqueKeysWithValues: assetsBriefMetadata.map { ($0.nftUid, $0) }) assetsBriefMetadataRelay.accept(map) } - } extension NftMetadataService { - var assetsBriefMetadataObservable: Observable<[NftUid: NftAssetBriefMetadata]> { assetsBriefMetadataRelay.asObservable() } @@ -35,11 +33,10 @@ extension NftMetadataService { func fetch(nftUids: Set) { nftMetadataManager.assetsBriefMetadataSingle(nftUids: nftUids) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onSuccess: { [weak self] assetsBriefMetadata in - self?.handle(assetsBriefMetadata: assetsBriefMetadata) - }) - .disposed(by: disposeBag) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onSuccess: { [weak self] assetsBriefMetadata in + self?.handle(assetsBriefMetadata: assetsBriefMetadata) + }) + .disposed(by: disposeBag) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroup.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroup.swift index 5d65850783..6c4ad87dff 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroup.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroup.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxRelay +import RxSwift class PoolGroup { private let pools: [Pool] @@ -18,12 +18,12 @@ class PoolGroup { init(pools: [Pool]) { self.pools = pools - Observable.merge(pools.map { $0.syncingObservable }) - .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onNext: { [weak self] _ in - self?.syncState() - }) - .disposed(by: disposeBag) + Observable.merge(pools.map(\.syncingObservable)) + .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onNext: { [weak self] _ in + self?.syncState() + }) + .disposed(by: disposeBag) syncState() } @@ -38,34 +38,31 @@ class PoolGroup { syncing = false } - } extension PoolGroup { - var syncingObservable: Observable { syncingRelay.asObservable() } - var invalidatedObservable: Observable<()> { - Observable.merge(pools.map { $0.invalidatedObservable }) + var invalidatedObservable: Observable { + Observable.merge(pools.map(\.invalidatedObservable)) } var itemsUpdatedObservable: Observable<[TransactionItem]> { - Observable.merge(pools.map { $0.itemsUpdatedObservable }) + Observable.merge(pools.map(\.itemsUpdatedObservable)) } func itemsSingle(count: Int) -> Single<[TransactionItem]> { let singles = pools.map { pool in pool.itemsSingle(count: count) - .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) } return Single.zip(singles) - .map { itemsArray in - let allItems = itemsArray.flatMap { $0 } - return Array(allItems.sorted().prefix(count)) - } + .map { itemsArray in + let allItems = itemsArray.flatMap { $0 } + return Array(allItems.sorted().prefix(count)) + } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroupFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroupFactory.swift index ec85ee46a1..95deb67704 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroupFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolGroupFactory.swift @@ -1,12 +1,11 @@ import Foundation -import RxSwift import MarketKit +import RxSwift class PoolGroupFactory { - private func providers(poolGroupType: PoolGroupType, filter: TransactionTypeFilter) -> [PoolProvider] { switch poolGroupType { - case .all(let wallets): + case let .all(wallets): var poolSources = Set() for wallet in wallets { @@ -14,15 +13,15 @@ class PoolGroupFactory { if App.shared.evmBlockchainManager.allBlockchains.contains(where: { $0 == wallet.token.blockchain }) || wallet.token.blockchainType == .tron { poolSource = PoolSource( - token: nil, - blockchainType: wallet.token.blockchainType, - filter: filter + token: nil, + blockchainType: wallet.token.blockchainType, + filter: filter ) } else { poolSource = PoolSource( - token: wallet.token, - blockchainType: wallet.token.blockchainType, - filter: filter + token: wallet.token, + blockchainType: wallet.token.blockchainType, + filter: filter ) } @@ -37,12 +36,12 @@ class PoolGroupFactory { } } - case .blockchain(let blockchainType, let wallets): + case let .blockchain(blockchainType, wallets): if App.shared.evmBlockchainManager.allBlockchains.contains(where: { $0.type == blockchainType }) || blockchainType == .tron { let poolSource = PoolSource( - token: nil, - blockchainType: blockchainType, - filter: filter + token: nil, + blockchainType: blockchainType, + filter: filter ) if let adapter = App.shared.transactionAdapterManager.adapter(for: poolSource.transactionSource) { @@ -57,9 +56,9 @@ class PoolGroupFactory { } let poolSource = PoolSource( - token: wallet.token, - blockchainType: blockchainType, - filter: filter + token: wallet.token, + blockchainType: blockchainType, + filter: filter ) if let adapter = App.shared.transactionAdapterManager.adapter(for: poolSource.transactionSource) { @@ -70,11 +69,11 @@ class PoolGroupFactory { return providers } - case .token(let token): + case let .token(token): let poolSource = PoolSource( - token: token, - blockchainType: token.blockchainType, - filter: filter + token: token, + blockchainType: token.blockchainType, + filter: filter ) if let adapter = App.shared.transactionAdapterManager.adapter(for: poolSource.transactionSource) { @@ -85,11 +84,9 @@ class PoolGroupFactory { return [] } - } extension PoolGroupFactory { - func poolGroup(type: PoolGroupType, filter: TransactionTypeFilter, scamFilterEnabled: Bool) -> PoolGroup { let providers = providers(poolGroupType: type, filter: filter) let pools = providers.map { poolProvider in @@ -97,15 +94,12 @@ extension PoolGroupFactory { } return PoolGroup(pools: pools) } - } extension PoolGroupFactory { - enum PoolGroupType { case all(wallets: [Wallet]) case blockchain(blockchainType: BlockchainType, wallets: [Wallet]) case token(token: Token) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolSource.swift index fea5db9991..6d1a41a881 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Pool/PoolSource.swift @@ -8,22 +8,20 @@ struct PoolSource { var transactionSource: TransactionSource { TransactionSource( - blockchainType: blockchainType, - meta: token?.type.meta + blockchainType: blockchainType, + meta: token?.type.meta ) } } extension PoolSource: Hashable { - public func hash(into hasher: inout Hasher) { hasher.combine(token) hasher.combine(blockchainType) hasher.combine(filter) } - public static func ==(lhs: PoolSource, rhs: PoolSource) -> Bool { + public static func == (lhs: PoolSource, rhs: PoolSource) -> Bool { lhs.token == rhs.token && lhs.blockchainType == rhs.blockchainType && lhs.filter == rhs.filter } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionFilterService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionFilterService.swift index b2862e6d69..c563669f72 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionFilterService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionFilterService.swift @@ -8,10 +8,10 @@ class TransactionFilterService { var allTokens = [Token]() func handle(wallets: [Wallet]) { - allBlockchains = Array(Set(wallets.map { $0.token.blockchain })) + allBlockchains = Array(Set(wallets.map(\.token.blockchain))) .sorted { $0.type.order < $1.type.order } - allTokens = wallets.map { $0.token } + allTokens = wallets.map(\.token) .sorted { lhsToken, rhsToken in let lhsName = lhsToken.coin.name.lowercased() let rhsName = rhsToken.coin.name.lowercased() diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionLockInfo.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionLockInfo.swift index 6cd4ff23e9..14faec78f6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionLockInfo.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionLockInfo.swift @@ -9,5 +9,4 @@ struct TransactionLockInfo { self.lockedUntil = lockedUntil self.originalAddress = originalAddress } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionSource.swift index 1888f412e6..6a34f35f6c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionSource.swift @@ -9,8 +9,7 @@ struct TransactionSource: Hashable { hasher.combine(meta) } - static func ==(lhs: TransactionSource, rhs: TransactionSource) -> Bool { + static func == (lhs: TransactionSource, rhs: TransactionSource) -> Bool { lhs.blockchainType == rhs.blockchainType && lhs.meta == rhs.meta } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsTableViewDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsTableViewDataSource.swift index d30dd8593f..27d7ab0e98 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsTableViewDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsTableViewDataSource.swift @@ -1,9 +1,9 @@ import Combine -import UIKit -import SnapKit +import ComponentKit import RxSwift +import SnapKit import ThemeKit -import ComponentKit +import UIKit class TransactionsTableViewDataSource: NSObject { private let viewModel: BaseTransactionsViewModel @@ -66,7 +66,7 @@ class TransactionsTableViewDataSource: NSObject { } } - private func sync(syncing: Bool) { + private func sync(syncing _: Bool) { // todo } @@ -76,21 +76,21 @@ class TransactionsTableViewDataSource: NSObject { component.set(progress: viewItem.progress) switch viewItem.iconType { - case .icon(let imageUrl, let placeholderImageName): + case let .icon(imageUrl, placeholderImageName): component.setImage( - urlString: imageUrl, - placeholder: UIImage(named: placeholderImageName) + urlString: imageUrl, + placeholder: UIImage(named: placeholderImageName) ) - case .localIcon(let imageName): + case let .localIcon(imageName): component.set(image: imageName.flatMap { UIImage(named: $0)?.withTintColor(.themeLeah) }) case let .doubleIcon(frontType, frontUrl, frontPlaceholder, backType, backUrl, backPlaceholder): component.setDoubleImage( - frontType: frontType, - frontUrl: frontUrl, - frontPlaceholder: UIImage(named: frontPlaceholder), - backType: backType, - backUrl: backUrl, - backPlaceholder: UIImage(named: backPlaceholder) + frontType: frontType, + frontUrl: frontUrl, + frontPlaceholder: UIImage(named: frontPlaceholder), + backType: backType, + backUrl: backUrl, + backPlaceholder: UIImage(named: backPlaceholder) ) case .failedIcon: component.set(image: UIImage(named: "warning_2_20")?.withTintColor(.themeLucian), contentMode: .center) @@ -130,7 +130,7 @@ class TransactionsTableViewDataSource: NSObject { } else { component.isHidden = true } - } + }, ]), .margin(1), .hStack([ @@ -151,16 +151,14 @@ class TransactionsTableViewDataSource: NSObject { } else { component.isHidden = true } - } - ]) - ]) - ], { component in component.alpha = viewItem.spam ? 0.25 : 1 }) + }, + ]), + ]), + ]) { component in component.alpha = viewItem.spam ? 0.25 : 1 } } - } extension TransactionsTableViewDataSource: ISectionDataSource { - func prepare(tableView: UITableView) { tableView.tableFooterView = UIView(frame: .zero) tableView.estimatedRowHeight = 0 @@ -181,7 +179,7 @@ extension TransactionsTableViewDataSource: ISectionDataSource { loaded = true } - func numberOfSections(in tableView: UITableView) -> Int { + func numberOfSections(in _: UITableView) -> Int { if sectionViewItems.isEmpty { return 1 } else { @@ -189,7 +187,7 @@ extension TransactionsTableViewDataSource: ISectionDataSource { } } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { if sectionViewItems.isEmpty { return 1 } else if section < sectionViewItems.count { @@ -206,11 +204,11 @@ extension TransactionsTableViewDataSource: ISectionDataSource { return tableView.dequeueReusableCell(withIdentifier: String(describing: PlaceholderCell.self), for: originalIndexPath) } else if indexPath.section < sectionViewItems.count { return CellBuilderNew.preparedCell( - tableView: tableView, - indexPath: originalIndexPath, - selectable: true, - rootElement: rootElement(viewItem: sectionViewItems[indexPath.section].viewItems[indexPath.row]), - layoutMargins: UIEdgeInsets(top: 0, left: .margin6, bottom: 0, right: .margin16) + tableView: tableView, + indexPath: originalIndexPath, + selectable: true, + rootElement: rootElement(viewItem: sectionViewItems[indexPath.section].viewItems[indexPath.row]), + layoutMargins: UIEdgeInsets(top: 0, left: .margin6, bottom: 0, right: .margin16) ) } else if indexPath.section == numberOfSections(in: tableView) - 1 { return tableView.dequeueReusableCell(withIdentifier: String(describing: EmptyCell.self), for: originalIndexPath) @@ -219,7 +217,7 @@ extension TransactionsTableViewDataSource: ISectionDataSource { } } - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { if sectionViewItems.isEmpty { if let cell = cell as? PlaceholderCell { cell.set(backgroundStyle: .transparent, isFirst: true) @@ -259,7 +257,7 @@ extension TransactionsTableViewDataSource: ISectionDataSource { } } - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + func tableView(_: UITableView, heightForHeaderInSection section: Int) -> CGFloat { section < sectionViewItems.count ? .heightSingleLineCell : 0 } @@ -271,12 +269,11 @@ extension TransactionsTableViewDataSource: ISectionDataSource { } } - func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { + func tableView(_: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { guard let view = view as? TransactionDateHeaderView else { return } view.text = sectionViewItems[section].title } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsViewItemFactory.swift index 4811a1deb9..4f8d3d1ed6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/TransactionsViewItemFactory.swift @@ -78,7 +78,7 @@ class TransactionsViewItemFactory { let backUrl: String? let backPlaceholder: String - if let primaryValue = primaryValue { + if let primaryValue { switch primaryValue { case let .nftValue(nftUid, _, _, _): frontType = .squircle @@ -95,7 +95,7 @@ class TransactionsViewItemFactory { frontPlaceholder = "placeholder_circle_32" } - if let secondaryValue = secondaryValue { + if let secondaryValue { switch secondaryValue { case let .nftValue(nftUid, _, _, _): backType = .squircle @@ -140,24 +140,24 @@ class TransactionsViewItemFactory { primaryValue = BaseTransactionsViewModel.Value(text: coinString(from: outgoingValue), type: type(value: outgoingValue, .outgoing)) secondaryValue = singleValueSecondaryValue(value: outgoingValue, currencyValue: currencyValue, nftMetadata: nftMetadata) } else if !incomingValues.isEmpty, outgoingValues.isEmpty { - let coinCodes = incomingValues.map { $0.coinCode }.joined(separator: ", ") + let coinCodes = incomingValues.map(\.coinCode).joined(separator: ", ") primaryValue = BaseTransactionsViewModel.Value(text: coinCodes, type: .incoming) secondaryValue = BaseTransactionsViewModel.Value(text: "transactions.multiple".localized, type: .secondary) } else if incomingValues.isEmpty, !outgoingValues.isEmpty { - let coinCodes = outgoingValues.map { $0.coinCode }.joined(separator: ", ") + let coinCodes = outgoingValues.map(\.coinCode).joined(separator: ", ") primaryValue = BaseTransactionsViewModel.Value(text: coinCodes, type: .outgoing) secondaryValue = BaseTransactionsViewModel.Value(text: "transactions.multiple".localized, type: .secondary) } else { if incomingValues.count == 1 { primaryValue = BaseTransactionsViewModel.Value(text: coinString(from: incomingValues[0]), type: type(value: incomingValues[0], .incoming)) } else { - let incomingCoinCodes = incomingValues.map { $0.coinCode }.joined(separator: ", ") + let incomingCoinCodes = incomingValues.map(\.coinCode).joined(separator: ", ") primaryValue = BaseTransactionsViewModel.Value(text: incomingCoinCodes, type: .incoming) } if outgoingValues.count == 1 { secondaryValue = BaseTransactionsViewModel.Value(text: coinString(from: outgoingValues[0]), type: type(value: outgoingValues[0], .outgoing)) } else { - let outgoingCoinCodes = outgoingValues.map { $0.coinCode }.joined(separator: ", ") + let outgoingCoinCodes = outgoingValues.map(\.coinCode).joined(separator: ", ") secondaryValue = BaseTransactionsViewModel.Value(text: outgoingCoinCodes, type: .outgoing) } } @@ -251,7 +251,7 @@ class TransactionsViewItemFactory { if record.outgoingEvents.isEmpty { title = "transactions.receive".localized - let addresses = Array(Set(record.incomingEvents.map { $0.address })) + let addresses = Array(Set(record.incomingEvents.map(\.address))) if addresses.count == 1 { subTitle = "transactions.from".localized(mapped(address: addresses[0], blockchainType: item.record.source.blockchainType)) } else { @@ -375,7 +375,7 @@ class TransactionsViewItemFactory { if record.outgoingEvents.isEmpty { title = "transactions.receive".localized - let addresses = Array(Set(record.incomingEvents.map { $0.address })) + let addresses = Array(Set(record.incomingEvents.map(\.address))) if addresses.count == 1 { subTitle = "transactions.from".localized(mapped(address: addresses[0], blockchainType: item.record.source.blockchainType)) } else { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Views/TransactionDateHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Views/TransactionDateHeaderView.swift index 24c35bf425..9b03f284e4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Views/TransactionDateHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Transactions/Views/TransactionDateHeaderView.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class TransactionDateHeaderView: UITableViewHeaderFooterView { private let label = UILabel() @@ -20,7 +20,8 @@ class TransactionDateHeaderView: UITableViewHeaderFooterView { label.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -28,5 +29,4 @@ class TransactionDateHeaderView: UITableViewHeaderFooterView { get { label.text } set { label.text = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/BalanceViewItem.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/BalanceViewItem.swift index cc629f96da..b30b263dfe 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/BalanceViewItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/BalanceViewItem.swift @@ -1,5 +1,5 @@ -import Foundation import DeepDiff +import Foundation import MarketKit struct BalanceViewItem { @@ -42,55 +42,48 @@ enum BalanceDiffType { } extension BalanceTopViewItem: Equatable { - - static func ==(lhs: BalanceTopViewItem, rhs: BalanceTopViewItem) -> Bool { + static func == (lhs: BalanceTopViewItem, rhs: BalanceTopViewItem) -> Bool { lhs.isMainNet == rhs.isMainNet && - lhs.iconUrlString == rhs.iconUrlString && - lhs.name == rhs.name && - lhs.blockchainBadge == rhs.blockchainBadge && - lhs.syncSpinnerProgress == rhs.syncSpinnerProgress && - lhs.indefiniteSearchCircle == rhs.indefiniteSearchCircle && - lhs.failedImageViewVisible == rhs.failedImageViewVisible && - lhs.primaryValue?.text == rhs.primaryValue?.text && - lhs.primaryValue?.dimmed == rhs.primaryValue?.dimmed && - lhs.secondaryInfo == rhs.secondaryInfo + lhs.iconUrlString == rhs.iconUrlString && + lhs.name == rhs.name && + lhs.blockchainBadge == rhs.blockchainBadge && + lhs.syncSpinnerProgress == rhs.syncSpinnerProgress && + lhs.indefiniteSearchCircle == rhs.indefiniteSearchCircle && + lhs.failedImageViewVisible == rhs.failedImageViewVisible && + lhs.primaryValue?.text == rhs.primaryValue?.text && + lhs.primaryValue?.dimmed == rhs.primaryValue?.dimmed && + lhs.secondaryInfo == rhs.secondaryInfo } - } extension BalanceSecondaryInfoViewItem: Equatable { - - static func ==(lhs: BalanceSecondaryInfoViewItem, rhs: BalanceSecondaryInfoViewItem) -> Bool { + static func == (lhs: BalanceSecondaryInfoViewItem, rhs: BalanceSecondaryInfoViewItem) -> Bool { switch (lhs, rhs) { - case (.amount(let lhsViewItem), .amount(let rhsViewItem)): + case let (.amount(lhsViewItem), .amount(rhsViewItem)): return lhsViewItem == rhsViewItem - case (.syncing(let lhsProgress, let lhsSyncedUntil), .syncing(let rhsProgress, let rhsSyncedUntil)): + case let (.syncing(lhsProgress, lhsSyncedUntil), .syncing(rhsProgress, rhsSyncedUntil)): return lhsProgress == rhsProgress && - lhsSyncedUntil == rhsSyncedUntil - case (.customSyncing(let lMain, let lSecondary), .customSyncing(let rMain, let rSecondary)): + lhsSyncedUntil == rhsSyncedUntil + case let (.customSyncing(lMain, lSecondary), .customSyncing(rMain, rSecondary)): return lMain == rMain && - lSecondary ?? "" == rSecondary ?? "" + lSecondary ?? "" == rSecondary ?? "" default: return false } } - } extension BalanceSecondaryAmountViewItem: Equatable { - - static func ==(lhs: BalanceSecondaryAmountViewItem, rhs: BalanceSecondaryAmountViewItem) -> Bool { + static func == (lhs: BalanceSecondaryAmountViewItem, rhs: BalanceSecondaryAmountViewItem) -> Bool { lhs.secondaryValue?.text == rhs.secondaryValue?.text && - lhs.secondaryValue?.dimmed == rhs.secondaryValue?.dimmed && - lhs.descriptionValue.text == rhs.descriptionValue.text && - lhs.descriptionValue.dimmed == rhs.descriptionValue.dimmed && - lhs.diff?.text == rhs.diff?.text && - lhs.diff?.type == rhs.diff?.type + lhs.secondaryValue?.dimmed == rhs.secondaryValue?.dimmed && + lhs.descriptionValue.text == rhs.descriptionValue.text && + lhs.descriptionValue.dimmed == rhs.descriptionValue.dimmed && + lhs.diff?.text == rhs.diff?.text && + lhs.diff?.type == rhs.diff?.type } - } extension BalanceViewItem: DiffAware { - public var diffId: WalletModule.Element { element } @@ -98,41 +91,32 @@ extension BalanceViewItem: DiffAware { static func compareContent(_ a: BalanceViewItem, _ b: BalanceViewItem) -> Bool { a.topViewItem == b.topViewItem } - } extension BalanceViewItem: CustomStringConvertible { - var description: String { "[topViewItem: \(topViewItem); buttonsViewItem: ]" } - } extension BalanceTopViewItem: CustomStringConvertible { - var description: String { "[iconUrlString: \(iconUrlString ?? "nil"); name: \(name); blockchainBadge: \(blockchainBadge ?? "nil"); syncSpinnerProgress: \(syncSpinnerProgress.map { "\($0)" } ?? "nil"); indefiniteSearchCircle: \(indefiniteSearchCircle); failedImageViewVisible: \(failedImageViewVisible); primaryValue: \(primaryValue.map { "[text: \($0.text ?? "nil"); dimmed: \($0.dimmed)]" } ?? "nil"); secondaryInfo: \(secondaryInfo)]" } - } extension BalanceSecondaryInfoViewItem: CustomStringConvertible { - var description: String { switch self { - case .amount(let viewItem): return "[amount: \(viewItem)]" - case .syncing(let progress, let syncedUntil): return "[syncing: [progress: \(progress.map { "\($0)" } ?? "nil"); syncedUntil: \(syncedUntil ?? "nil")]]" - case .customSyncing(let left, let right): return "[\([left, right].compactMap { $0 }.joined(separator: " : "))]" + case let .amount(viewItem): return "[amount: \(viewItem)]" + case let .syncing(progress, syncedUntil): return "[syncing: [progress: \(progress.map { "\($0)" } ?? "nil"); syncedUntil: \(syncedUntil ?? "nil")]]" + case let .customSyncing(left, right): return "[\([left, right].compactMap { $0 }.joined(separator: " : "))]" } } - } extension BalanceSecondaryAmountViewItem: CustomStringConvertible { - var description: String { "[secondaryValue: \(secondaryValue.map { "[text: \($0.text ?? "nil"); dimmed: \($0.dimmed)]" } ?? "nil"); rateValue: \("[text: \(descriptionValue.text ?? "nil"); dimmed: \(descriptionValue.dimmed)]"); diff: \(diff.map { "[text: \($0.text); type: \($0.type)]" } ?? "nil")]" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/EnabledWalletCacheManager.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/EnabledWalletCacheManager.swift index d59ac8a396..5da45da6e2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/EnabledWalletCacheManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/EnabledWalletCacheManager.swift @@ -13,11 +13,9 @@ class EnabledWalletCacheManager { private func handleDelete(account: Account) { storage.deleteEnabledWalletCaches(accountId: account.id) } - } extension EnabledWalletCacheManager { - func cacheContainer(accountId: String) -> CacheContainer { CacheContainer(caches: storage.enabledWalletCaches(accountId: accountId)) } @@ -33,11 +31,9 @@ extension EnabledWalletCacheManager { let cache = EnabledWalletCache(wallet: wallet, balanceData: balanceData) storage.save(enabledWalletCaches: [cache]) } - } extension EnabledWalletCacheManager { - struct CacheContainer { private let caches: [EnabledWalletCache] @@ -49,5 +45,4 @@ extension EnabledWalletCacheManager { caches.first { $0.tokenQueryId == wallet.token.tokenQuery.id }?.balanceData } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressModule.swift index a8bc42a515..11faefff4d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressModule.swift @@ -1,9 +1,8 @@ import Foundation -import UIKit import SwiftUI +import UIKit class ReceiveAddressModule { - static func view(wallet: Wallet) -> some View { let service = ReceiveAddressService(wallet: wallet, adapterManager: App.shared.adapterManager) let depositViewItemFactory = ReceiveAddressViewItemFactory() @@ -11,17 +10,15 @@ class ReceiveAddressModule { let viewModel = ReceiveAddressViewModel(service: service, viewItemFactory: depositViewItemFactory, decimalParser: AmountDecimalParser()) return ReceiveAddressView(viewModel: viewModel) } - } extension ReceiveAddressModule { - struct ErrorItem: Error { let icon: String let text: String - let retryAction: (() -> ())? + let retryAction: (() -> Void)? - init(icon: String, text: String, retryAction: (() -> ())? = nil) { + init(icon: String, text: String, retryAction: (() -> Void)? = nil) { self.icon = icon self.text = text self.retryAction = retryAction @@ -44,9 +41,9 @@ extension ReceiveAddressModule { let description: DescriptionItem let doneButtonTitle: String - static func ==(lhs: PopupWarningItem, rhs: PopupWarningItem) -> Bool { - lhs.title == rhs.title && - lhs.description.text == rhs.description.text + static func == (lhs: PopupWarningItem, rhs: PopupWarningItem) -> Bool { + lhs.title == rhs.title && + lhs.description.text == rhs.description.text } public var id: String { @@ -100,7 +97,7 @@ extension ReceiveAddressModule { hasher.combine(id) } - static func ==(lhs: Item, rhs: Item) -> Bool { + static func == (lhs: Item, rhs: Item) -> Bool { lhs.id == rhs.id } } @@ -109,5 +106,4 @@ extension ReceiveAddressModule { let copyValue: String let sections: [[Item]] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressService.swift index aab34bde15..e7ad0efec1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressService.swift @@ -1,9 +1,9 @@ import Combine import Foundation +import HsExtensions import MarketKit -import RxSwift import RxCocoa -import HsExtensions +import RxSwift class ReceiveAddressService { typealias ServiceItem = Item @@ -19,6 +19,7 @@ class ReceiveAddressService { stateUpdatedSubject.send(state) } } + private let stateUpdatedSubject = PassthroughSubject, Never>() private var adapter: IDepositAdapter? @@ -56,10 +57,10 @@ class ReceiveAddressService { let isMainNet = adapter.isMainNet adapter.receiveAddressPublisher - .sink { [weak self] status in - self?.updateStatus(status: status, isMainNet: isMainNet) - } - .store(in: &cancellables) + .sink { [weak self] status in + self?.updateStatus(status: status, isMainNet: isMainNet) + } + .store(in: &cancellables) updateStatus(status: adapter.receiveAddressStatus, isMainNet: isMainNet) } @@ -67,20 +68,18 @@ class ReceiveAddressService { private func updateStatus(status: DataStatus, isMainNet: Bool) { state = status.map { address in Item( - address: address, - token: wallet.token, - isMainNet: isMainNet, - watchAccount: wallet.account.watchAccount, - coinCode: wallet.coin.code, - imageUrl: wallet.coin.imageUrl + address: address, + token: wallet.token, + isMainNet: isMainNet, + watchAccount: wallet.account.watchAccount, + coinCode: wallet.coin.code, + imageUrl: wallet.coin.imageUrl ) } } - } extension ReceiveAddressService: IReceiveAddressService { - var title: String { "deposit.receive_coin".localized(wallet.coin.code) } @@ -88,11 +87,9 @@ extension ReceiveAddressService: IReceiveAddressService { var statusUpdatedPublisher: AnyPublisher, Never> { stateUpdatedSubject.eraseToAnyPublisher() } - } extension ReceiveAddressService { - struct Item { let address: DepositAddress let token: Token @@ -111,5 +108,4 @@ extension ReceiveAddressService { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressView.swift index 9f1bce2069..2bf2e5ad83 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Address/ReceiveAddressView.swift @@ -29,7 +29,7 @@ struct ReceiveAddressView UIViewController? { guard let account = App.shared.accountManager.activeAccount else { return nil } let service = ReceiveService( - account: account, - walletManager: App.shared.walletManager, - marketKit: App.shared.marketKit, - restoreSettingsService: RestoreSettingsService(manager: App.shared.restoreSettingsManager) + account: account, + walletManager: App.shared.walletManager, + marketKit: App.shared.marketKit, + restoreSettingsService: RestoreSettingsService(manager: App.shared.restoreSettingsManager) ) let viewModel = ReceiveViewModel(service: service) let coinProvider = CoinProvider( - marketKit: App.shared.marketKit, - walletManager: App.shared.walletManager, - accountType: account.type + marketKit: App.shared.marketKit, + walletManager: App.shared.walletManager, + accountType: account.type ) let selectCoinService = ReceiveSelectCoinService(provider: coinProvider) @@ -32,7 +31,7 @@ struct ReceiveModule { return ReceiveViewController(rootViewController: viewController, viewModel: viewModel) } - static func selectTokenViewController(fullCoin: FullCoin, accountType: AccountType, onSelect: ((Token) -> ())?) -> UIViewController { + static func selectTokenViewController(fullCoin: FullCoin, accountType: AccountType, onSelect: ((Token) -> Void)?) -> UIViewController { let viewModel = ReceiveTokenViewModel(fullCoin: fullCoin, accountType: accountType) let viewController = ReceiveSelectorViewController(viewModel: viewModel) @@ -41,7 +40,7 @@ struct ReceiveModule { return viewController } - static func selectDerivationViewController(wallets: [Wallet], onSelect: ((Wallet) -> ())?) -> UIViewController { + static func selectDerivationViewController(wallets: [Wallet], onSelect: ((Wallet) -> Void)?) -> UIViewController { let viewModel = ReceiveDerivationViewModel(wallets: wallets) let viewController = ReceiveSelectorViewController(viewModel: viewModel) @@ -50,7 +49,7 @@ struct ReceiveModule { return viewController } - static func selectBitcoinCashCoinTypeViewController(wallets: [Wallet], onSelect: ((Wallet) -> ())?) -> UIViewController { + static func selectBitcoinCashCoinTypeViewController(wallets: [Wallet], onSelect: ((Wallet) -> Void)?) -> UIViewController { let viewModel = ReceiveBitcoinCashCoinTypeViewModel(wallets: wallets) let viewController = ReceiveSelectorViewController(viewModel: viewModel) @@ -58,5 +57,4 @@ struct ReceiveModule { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewController.swift index f8c87f505a..ef618a9ebd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewController.swift @@ -1,7 +1,7 @@ import Combine -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit class ReceiveViewController: ThemeNavigationController { private let viewModel: ReceiveViewModel @@ -16,42 +16,43 @@ class ReceiveViewController: ThemeNavigationController { } viewModel.showTokenPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] wallet in - self?.showReceive(wallet: wallet) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] wallet in + self?.showReceive(wallet: wallet) + } + .store(in: &cancellables) viewModel.showDerivationSelectPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] wallets in - self?.showDerivationSelect(wallets: wallets) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] wallets in + self?.showDerivationSelect(wallets: wallets) + } + .store(in: &cancellables) viewModel.showBitcoinCashCoinTypeSelectPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] wallets in - self?.showBitcoinCashCoinTypeSelect(wallets: wallets) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] wallets in + self?.showBitcoinCashCoinTypeSelect(wallets: wallets) + } + .store(in: &cancellables) viewModel.showZcashRestoreSelectPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] token in - self?.showZcashRestoreSelect(token: token) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] token in + self?.showZcashRestoreSelect(token: token) + } + .store(in: &cancellables) viewModel.showBlockchainSelectPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] (fullCoin, accountType) in - self?.showBlockchainSelect(fullCoin: fullCoin, accountType: accountType) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] fullCoin, accountType in + self?.showBlockchainSelect(fullCoin: fullCoin, accountType: accountType) + } + .store(in: &cancellables) } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -76,20 +77,21 @@ class ReceiveViewController: ThemeNavigationController { private func showZcashRestoreSelect(token: Token) { let viewController = BottomSheetModule.viewController( - image: .remote(url: token.coin.imageUrl, placeholder: "placeholder_circle_32"), - title: token.coin.code, - subtitle: token.coin.name, - items: [ - .description(text: "deposit.zcash.restore.description".localized) - ], - buttons: [ - .init(style: .yellow, title: "deposit.zcash.restore.already_own".localized, actionType: .afterClose, action: { [weak self] in - self?.showRestoreZcash(token: token) - }), - .init(style: .gray, title: "deposit.zcash.restore.dont_have".localized, actionType: .afterClose, action: { [weak self] in - self?.viewModel.onRestoreZcash(token: token, height: nil) - }), - ]) + image: .remote(url: token.coin.imageUrl, placeholder: "placeholder_circle_32"), + title: token.coin.code, + subtitle: token.coin.name, + items: [ + .description(text: "deposit.zcash.restore.description".localized), + ], + buttons: [ + .init(style: .yellow, title: "deposit.zcash.restore.already_own".localized, actionType: .afterClose, action: { [weak self] in + self?.showRestoreZcash(token: token) + }), + .init(style: .gray, title: "deposit.zcash.restore.dont_have".localized, actionType: .afterClose, action: { [weak self] in + self?.viewModel.onRestoreZcash(token: token, height: nil) + }), + ] + ) present(viewController, animated: true) } @@ -108,11 +110,9 @@ class ReceiveViewController: ThemeNavigationController { } present(ThemeNavigationController(rootViewController: viewController), animated: true) } - } extension ReceiveViewController { - func onSelect(fullCoin: FullCoin) { viewModel.onSelect(fullCoin: fullCoin) } @@ -120,5 +120,4 @@ extension ReceiveViewController { func onSelectExact(token: Token) { viewModel.onSelectExact(token: token) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewModel.swift index 6fb96cb445..bdb38eee64 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/ReceiveViewModel.swift @@ -8,11 +8,9 @@ class ReceiveViewModel { init(service: ReceiveService) { self.service = service } - } extension ReceiveViewModel { - func onSelect(fullCoin: FullCoin) { service.onSelect(fullCoin: fullCoin) } @@ -24,11 +22,9 @@ extension ReceiveViewModel { func onRestoreZcash(token: Token, height: Int?) { service.onRestoreZcash(token: token, height: height) } - } extension ReceiveViewModel { - var showTokenPublisher: AnyPublisher { service.showTokenPublisher } @@ -48,5 +44,4 @@ extension ReceiveViewModel { var showBlockchainSelectPublisher: AnyPublisher<(FullCoin, AccountType), Never> { service.showBlockchainSelectPublisher } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/CoinProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/CoinProvider.swift index 0b67bde67d..243ad450ee 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/CoinProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/CoinProvider.swift @@ -24,10 +24,10 @@ class CoinProvider { private var nativeFullCoins: [FullCoin] { do { let blockchainTypes = BlockchainType.supported.sorted() - let queries = blockchainTypes.map { $0.nativeTokenQueries }.flatMap { $0 } + let queries = blockchainTypes.map(\.nativeTokenQueries).flatMap { $0 } let coinUids = try marketKit .tokens(queries: queries) - .map { $0.coin.uid } + .map(\.coin.uid) return try marketKit.fullCoins(coinUids: coinUids) } catch { @@ -40,11 +40,9 @@ class CoinProvider { fullCoin.coin.code.localizedCaseInsensitiveContains(filter) || fullCoin.coin.name.localizedCaseInsensitiveContains(filter) } } - } extension CoinProvider { - func fetch(filter: String) -> [FullCoin] { guard !filter.isEmpty else { return predefined @@ -61,31 +59,27 @@ extension CoinProvider { return [] } } - } extension CoinProvider { - var predefinedCoins: [FullCoin] { // get all restored coins let activeWallets = walletManager.activeWallets - let walletCoins = activeWallets.map { $0.coin } + let walletCoins = activeWallets.map(\.coin) // found account full coins - var walletFullCoins = (try? marketKit.fullCoins(coinUids: walletCoins.map { $0.uid })) ?? [] + var walletFullCoins = (try? marketKit.fullCoins(coinUids: walletCoins.map(\.uid))) ?? [] walletFullCoins.append(contentsOf: custom) // get all native coins for supported blockchains let nativeFullCoins = nativeFullCoins - // filter not supported by current account let predefined = (walletFullCoins + nativeFullCoins).removeDuplicates() .filter { fullCoin in - fullCoin.tokens.contains { accountType.supports(token: $0) } - } + fullCoin.tokens.contains { accountType.supports(token: $0) } + } return predefined } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewController.swift index f45ee9a202..2a0e21d2e8 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewController.swift @@ -1,11 +1,11 @@ +import Alamofire import Combine -import UIKit +import ComponentKit +import MarketKit import SectionsTableView import SnapKit import ThemeKit -import MarketKit -import ComponentKit -import Alamofire +import UIKit class ReceiveSelectCoinViewController: ThemeSearchViewController { private var cancellables = Set() @@ -15,7 +15,7 @@ class ReceiveSelectCoinViewController: ThemeSearchViewController { private let tableView = SectionsTableView(style: .grouped) private var viewItems = [ReceiveSelectCoinViewModel.ViewItem]() - var onSelect: ((FullCoin) -> ())? + var onSelect: ((FullCoin) -> Void)? init(viewModel: ReceiveSelectCoinViewModel) { self.viewModel = viewModel @@ -23,7 +23,8 @@ class ReceiveSelectCoinViewController: ThemeSearchViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -46,15 +47,15 @@ class ReceiveSelectCoinViewController: ThemeSearchViewController { navigationItem.searchController?.searchBar.placeholder = "placeholder.search".localized viewModel.$viewItems - .receive(on: DispatchQueue.main) - .sink { [weak self] viewItems in - self?.sync(viewItems: viewItems) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] viewItems in + self?.sync(viewItems: viewItems) + } + .store(in: &cancellables) $filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.viewModel.apply(filter: $0) } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.viewModel.apply(filter: $0) } + .store(in: &cancellables) sync(viewItems: viewModel.viewItems) } @@ -75,34 +76,31 @@ class ReceiveSelectCoinViewController: ThemeSearchViewController { tableView.reload() } - } extension ReceiveSelectCoinViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "coins", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - let isLast = index == viewItems.count - 1 - - return tableView.universalRow62( - id: viewItem.uid, - image: .url(viewItem.imageUrl, placeholder: "placeholder_circle_32"), - title: .body(viewItem.title), - description: .subhead2(viewItem.description), - backgroundStyle: .transparent, - autoDeselect: true, - isLast: isLast - ) { [weak self] in - self?.onSelect(uid: viewItem.uid) - } + id: "coins", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + let isLast = index == viewItems.count - 1 + + return tableView.universalRow62( + id: viewItem.uid, + image: .url(viewItem.imageUrl, placeholder: "placeholder_circle_32"), + title: .body(viewItem.title), + description: .subhead2(viewItem.description), + backgroundStyle: .transparent, + autoDeselect: true, + isLast: isLast + ) { [weak self] in + self?.onSelect(uid: viewItem.uid) } - ) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewModel.swift index 8730b88b20..eaece4363d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/SelectCoin/ReceiveSelectCoinViewModel.swift @@ -12,10 +12,10 @@ class ReceiveSelectCoinViewModel { self.service = service service.$coins - .sink { [weak self] coins in - self?.sync(coins: coins) - } - .store(in: &cancellables) + .sink { [weak self] coins in + self?.sync(coins: coins) + } + .store(in: &cancellables) sync(coins: service.coins) } @@ -25,11 +25,9 @@ class ReceiveSelectCoinViewModel { ViewItem(uid: fullCoin.coin.uid, imageUrl: fullCoin.coin.imageUrl, title: fullCoin.coin.code, description: fullCoin.coin.name) } } - } extension ReceiveSelectCoinViewModel { - func apply(filter: String?) { DispatchQueue.global(qos: .userInitiated).async { [weak self] in self?.service.set(filter: filter?.trimmingCharacters(in: .whitespaces) ?? "") @@ -39,16 +37,13 @@ extension ReceiveSelectCoinViewModel { func fullCoin(uid: String) -> FullCoin? { service.fullCoin(uid: uid) } - } extension ReceiveSelectCoinViewModel { - struct ViewItem { let uid: String let imageUrl: String? let title: String let description: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveBitcoinCashCoinTypeViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveBitcoinCashCoinTypeViewModel.swift index 8c696d4370..0058512f5c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveBitcoinCashCoinTypeViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveBitcoinCashCoinTypeViewModel.swift @@ -6,11 +6,9 @@ class ReceiveBitcoinCashCoinTypeViewModel: IReceiveSelectorViewModel { init(wallets: [Wallet]) { self.wallets = wallets } - } extension ReceiveBitcoinCashCoinTypeViewModel { - var viewItems: [ReceiveSelectorViewModel.ViewItem] { wallets.compactMap { wallet in guard let bitcoinCashCoinType = wallet.token.type.bitcoinCashCoinType else { @@ -18,10 +16,10 @@ extension ReceiveBitcoinCashCoinTypeViewModel { } return ReceiveSelectorViewModel.ViewItem( - uid: bitcoinCashCoinType.rawValue, - imageUrl: nil, - title: bitcoinCashCoinType.description + bitcoinCashCoinType.recommended, - subtitle: bitcoinCashCoinType.title.uppercased() + uid: bitcoinCashCoinType.rawValue, + imageUrl: nil, + title: bitcoinCashCoinType.description + bitcoinCashCoinType.recommended, + subtitle: bitcoinCashCoinType.title.uppercased() ) } } @@ -35,5 +33,4 @@ extension ReceiveBitcoinCashCoinTypeViewModel { var title: String { "receive_address_format_select.title".localized } var topDescription: String { "receive_address_format_select.description".localized } var highlightedBottomDescription: String? { "receive_address_format_select.bitcoin_cash.bottom_description".localized } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveDerivationViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveDerivationViewModel.swift index f5925e548d..b6ee54717a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveDerivationViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveDerivationViewModel.swift @@ -6,11 +6,9 @@ class ReceiveDerivationViewModel: IReceiveSelectorViewModel { init(wallets: [Wallet]) { self.wallets = wallets } - } extension ReceiveDerivationViewModel { - var viewItems: [ReceiveSelectorViewModel.ViewItem] { wallets.compactMap { wallet in guard let derivation = wallet.token.type.derivation else { @@ -18,10 +16,10 @@ extension ReceiveDerivationViewModel { } return ReceiveSelectorViewModel.ViewItem( - uid: derivation.rawValue, - imageUrl: nil, - title: derivation.addressType + derivation.recommended, - subtitle: derivation.title + uid: derivation.rawValue, + imageUrl: nil, + title: derivation.addressType + derivation.recommended, + subtitle: derivation.title ) } } @@ -35,5 +33,4 @@ extension ReceiveDerivationViewModel { var title: String { "receive_address_format_select.title".localized } var topDescription: String { "receive_address_format_select.description".localized } var highlightedBottomDescription: String? { "receive_address_format_select.bitcoin.bottom_description".localized } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveSelectorViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveSelectorViewController.swift index 53abc83cf3..034ab9447d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveSelectorViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/ReceiveSelectorViewController.swift @@ -1,13 +1,13 @@ import Foundation -import UIKit import MarketKit import SectionsTableView import ThemeKit +import UIKit class ReceiveSelectorViewController: ThemeViewController { private let viewModel: ViewModel - var onSelect: ((ViewModel.Item) -> ())? + var onSelect: ((ViewModel.Item) -> Void)? private let tableView = SectionsTableView(style: .grouped) @@ -17,7 +17,8 @@ class ReceiveSelectorViewController: Theme super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -55,64 +56,61 @@ class ReceiveSelectorViewController: Theme onSelect?(item) } - } extension ReceiveSelectorViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { let viewItems = viewModel.viewItems var sections: [SectionProtocol] = [ Section( - id: "description", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: [ - tableView.descriptionRow( - id: "description", - text: viewModel.topDescription, - font: .subhead2, - textColor: .themeGray, - ignoreBottomMargin: true - ) - ] + id: "description", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + tableView.descriptionRow( + id: "description", + text: viewModel.topDescription, + font: .subhead2, + textColor: .themeGray, + ignoreBottomMargin: true + ), + ] ), Section( - id: "main", - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - tableView.universalRow62( - id: viewItem.uid, - image: .url(viewItem.imageUrl, placeholder: "placeholder_rectangle_32"), - title: .body(viewItem.title), - description: .subhead2(viewItem.subtitle), - accessoryType: .disclosure, - isFirst: index == 0, - isLast: index == viewItems.count - 1) - { [weak self] in - self?.onSelect(uid: viewItem.uid) - } + id: "main", + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + tableView.universalRow62( + id: viewItem.uid, + image: .url(viewItem.imageUrl, placeholder: "placeholder_rectangle_32"), + title: .body(viewItem.title), + description: .subhead2(viewItem.subtitle), + accessoryType: .disclosure, + isFirst: index == 0, + isLast: index == viewItems.count - 1 + ) { [weak self] in + self?.onSelect(uid: viewItem.uid) } - ) + } + ), ] if let bottomDescription = viewModel.highlightedBottomDescription { sections.append( - Section( + Section( + id: "description", + footerState: .margin(height: .margin32), + rows: [ + tableView.highlightedDescriptionRow( id: "description", - footerState: .margin(height: .margin32), - rows: [ - tableView.highlightedDescriptionRow( - id: "description", - text: bottomDescription, - ignoreBottomMargin: true - ) - ] - ) + text: bottomDescription, + ignoreBottomMargin: true + ), + ] + ) ) } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/RecieveSelectorViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/RecieveSelectorViewModel.swift index 633262786d..915ae93b02 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/RecieveSelectorViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Receive/Selector/RecieveSelectorViewModel.swift @@ -11,13 +11,11 @@ protocol IReceiveSelectorViewModel { func item(uid: String) -> Item? } -class ReceiveSelectorViewModel { - +enum ReceiveSelectorViewModel { struct ViewItem { let uid: String let imageUrl: String? let title: String let subtitle: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCell.swift index ae3961d082..e7ec18935f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCell.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class WalletTokenBalanceCell: UITableViewCell { private let stackView = UIStackView() @@ -63,19 +63,20 @@ class WalletTokenBalanceCell: UITableViewCell { descriptionLabel.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } - func bind(viewItem: WalletTokenBalanceViewModel.ViewItem, onTapError: (() -> ())?) { + func bind(viewItem: WalletTokenBalanceViewModel.ViewItem, onTapError: (() -> Void)?) { testnetImageView.isHidden = viewItem.isMainNet coinIconView.bind( - iconUrlString: viewItem.iconUrlString, - placeholderIconName: viewItem.placeholderIconName, - spinnerProgress: viewItem.syncSpinnerProgress, - indefiniteSearchCircle: viewItem.indefiniteSearchCircle, - failViewVisible: viewItem.failedImageViewVisible, - onTapError: onTapError + iconUrlString: viewItem.iconUrlString, + placeholderIconName: viewItem.placeholderIconName, + spinnerProgress: viewItem.syncSpinnerProgress, + indefiniteSearchCircle: viewItem.indefiniteSearchCircle, + failViewVisible: viewItem.failedImageViewVisible, + onTapError: onTapError ) amountLabel.text = viewItem.balanceValue?.text ?? "----" @@ -85,15 +86,13 @@ class WalletTokenBalanceCell: UITableViewCell { descriptionLabel.textColor = (viewItem.descriptionValue?.dimmed ?? true) ? .themeGray50 : .themeGray } - var onTapAmount: (() -> ())? { + var onTapAmount: (() -> Void)? { get { amountButton.onTap } set { amountButton.onTap = newValue } } - } extension WalletTokenBalanceCell { - static func height(containerWidth: CGFloat, viewItem: WalletTokenBalanceViewModel.ViewItem?) -> CGFloat { var height: CGFloat = .margin24 + .iconSize32 + .margin12 height += (viewItem?.balanceValue?.text ?? "----").height(forContainerWidth: containerWidth - 2 * .margin16, font: .title2R) + .margin6 @@ -105,5 +104,4 @@ extension WalletTokenBalanceCell { return height } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCustomAmountCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCustomAmountCell.swift index 6a0cf0f5a5..39dc26c6e5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCustomAmountCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/Views/WalletTokenBalanceCustomAmountCell.swift @@ -1,13 +1,13 @@ -import UIKit import ComponentKit +import UIKit class WalletTokenBalanceCustomAmountCell: BaseSelectableThemeCell { - - override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style _: UITableViewCell.CellStyle, reuseIdentifier _: String?) { super.init(style: .default, reuseIdentifier: nil) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -17,7 +17,7 @@ class WalletTokenBalanceCustomAmountCell: BaseSelectableThemeCell { let elements: [CellBuilderNew.CellElement] = [ .textElement(text: .subhead2(title), parameters: .allCompression), .margin8, - .image20 { component in + .image20 { component in component.imageView.image = UIImage(named: "circle_information_20")?.withTintColor(.themeGray) }, .textElement(text: .subhead2(amount, color: valueColor), parameters: [.rightAlignment]), @@ -25,5 +25,4 @@ class WalletTokenBalanceCustomAmountCell: BaseSelectableThemeCell { CellBuilderNew.buildStatic(cell: self, rootElement: .hStack(elements)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceModule.swift index e497b8a9f8..370e4f4045 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceModule.swift @@ -1,40 +1,38 @@ import Foundation struct WalletTokenBalanceModule { - static func dataSource(element: WalletModule.Element) -> WalletTokenBalanceDataSource? { guard let account = App.shared.accountManager.activeAccount else { return nil } let coinPriceService = WalletCoinPriceService( - tag: "wallet-token-balance", - currencyManager: App.shared.currencyManager, - marketKit: App.shared.marketKit + tag: "wallet-token-balance", + currencyManager: App.shared.currencyManager, + marketKit: App.shared.marketKit ) let elementServiceFactory = WalletElementServiceFactory( - adapterManager: App.shared.adapterManager, - walletManager: App.shared.walletManager, - cexAssetManager: App.shared.cexAssetManager + adapterManager: App.shared.adapterManager, + walletManager: App.shared.walletManager, + cexAssetManager: App.shared.cexAssetManager ) let elementService = elementServiceFactory.elementService(account: account) let tokenBalanceService = WalletTokenBalanceService( - coinPriceService: coinPriceService, - elementService: elementService, - appManager: App.shared.appManager, - cloudAccountBackupManager: App.shared.cloudBackupManager, - balanceHiddenManager: App.shared.balanceHiddenManager, - reachabilityManager: App.shared.reachabilityManager, - account: account, - element: element + coinPriceService: coinPriceService, + elementService: elementService, + appManager: App.shared.appManager, + cloudAccountBackupManager: App.shared.cloudBackupManager, + balanceHiddenManager: App.shared.balanceHiddenManager, + reachabilityManager: App.shared.reachabilityManager, + account: account, + element: element ) let factory = WalletTokenBalanceViewItemFactory() let tokenBalanceViewModel = WalletTokenBalanceViewModel(service: tokenBalanceService, factory: factory) return WalletTokenBalanceDataSource(viewModel: tokenBalanceViewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceService.swift index ee0ef38528..d68de528c0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceService.swift @@ -1,7 +1,7 @@ import Combine import Foundation -import RxSwift import HsExtensions +import RxSwift class WalletTokenBalanceService { private let disposeBag = DisposeBag() @@ -24,7 +24,8 @@ class WalletTokenBalanceService { init(coinPriceService: WalletCoinPriceService, elementService: IWalletElementService, appManager: IAppManager, cloudAccountBackupManager: CloudBackupManager, balanceHiddenManager: BalanceHiddenManager, reachabilityManager: IReachabilityManager, - account: Account, element: WalletModule.Element) { + account: Account, element: WalletModule.Element) + { self.coinPriceService = coinPriceService self.elementService = elementService self.cloudAccountBackupManager = cloudAccountBackupManager @@ -58,11 +59,11 @@ class WalletTokenBalanceService { let priceItemMap = coinPriceService.itemMap(coinUids: [element.priceCoinUid].compactMap { $0 }) let item = BalanceItem( - element: element, - isMainNet: elementService.isMainNet(element: element) ?? fallbackIsMainNet, - watchAccount: account.watchAccount, - balanceData: elementService.balanceData(element: element) ?? fallbackBalanceData, - state: elementService.state(element: element) ?? fallbackAdapterState + element: element, + isMainNet: elementService.isMainNet(element: element) ?? fallbackIsMainNet, + watchAccount: account.watchAccount, + balanceData: elementService.balanceData(element: element) ?? fallbackBalanceData, + state: elementService.state(element: element) ?? fallbackAdapterState ) if let priceCoinUid = element.priceCoinUid { @@ -87,11 +88,9 @@ class WalletTokenBalanceService { var isReachable: Bool { reachabilityManager.isReachable } - } extension WalletTokenBalanceService { - var itemUpdatedPublisher: AnyPublisher { itemUpdatedSubject.eraseToAnyPublisher() } @@ -111,11 +110,9 @@ extension WalletTokenBalanceService { func toggleBalanceHidden() { balanceHiddenManager.toggleBalanceHidden() } - } extension WalletTokenBalanceService { - class BalanceItem { let element: WalletModule.Element var isMainNet: Bool @@ -132,18 +129,16 @@ extension WalletTokenBalanceService { self.state = state } } - } extension WalletTokenBalanceService: IWalletElementServiceDelegate { - - func didUpdate(elementState: WalletModule.ElementState, elementService: IWalletElementService) { + func didUpdate(elementState _: WalletModule.ElementState, elementService _: IWalletElementService) { queue.async { [weak self] in self?._sync() } } - func didUpdateElements(elementService: IWalletElementService) {} + func didUpdateElements(elementService _: IWalletElementService) {} func didUpdate(isMainNet: Bool, element: WalletModule.Element) { guard element == self.element else { @@ -174,12 +169,10 @@ extension WalletTokenBalanceService: IWalletElementServiceDelegate { self?.itemUpdatedSubject.send() } } - } extension WalletTokenBalanceService: IWalletCoinPriceServiceDelegate { - - private func _handleUpdated(priceItemMap: [String: WalletCoinPriceService.Item], items: [BalanceItem]) { + private func _handleUpdated(priceItemMap: [String: WalletCoinPriceService.Item], items _: [BalanceItem]) { queue.async { [weak self] in if let priceCoinUid = self?.element.priceCoinUid { self?.item?.priceItem = priceItemMap[priceCoinUid] @@ -189,6 +182,5 @@ extension WalletTokenBalanceService: IWalletCoinPriceServiceDelegate { } func didUpdateBaseCurrency() {} - func didUpdate(itemsMap: [String: WalletCoinPriceService.Item]) {} - + func didUpdate(itemsMap _: [String: WalletCoinPriceService.Item]) {} } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewItemFactory.swift index 1365fb84bb..9d8e41552a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewItemFactory.swift @@ -57,7 +57,7 @@ class WalletTokenBalanceViewItemFactory { private func descriptionValue(item: WalletTokenBalanceService.BalanceItem, balanceHidden: Bool) -> (text: String?, dimmed: Bool) { if case let .syncing(progress, lastBlockDate) = item.state { var text = "" - if let progress = progress { + if let progress { text = "balance.syncing_percent".localized("\(progress)%") } else { text = "balance.syncing".localized @@ -123,7 +123,7 @@ class WalletTokenBalanceViewItemFactory { } private func currencyValue(value: Decimal, balanceHidden: Bool, state: AdapterState, priceItem: WalletCoinPriceService.Item?) -> (text: String?, dimmed: Bool) { - guard let priceItem = priceItem else { + guard let priceItem else { return (text: "---", dimmed: true) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewModel.swift index 374bc62030..756466c2e3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/DataSources/WalletTokenBalance/WalletTokenBalanceViewModel.swift @@ -24,16 +24,16 @@ class WalletTokenBalanceViewModel { self.factory = factory service.$item - .sink { [weak self] in self?.sync(item: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(item: $0) } + .store(in: &cancellables) service.itemUpdatedPublisher - .sink { [weak self] in self?.sync() } - .store(in: &cancellables) + .sink { [weak self] in self?.sync() } + .store(in: &cancellables) service.balanceHiddenPublisher - .sink { [weak self] _ in self?.sync() } - .store(in: &cancellables) + .sink { [weak self] _ in self?.sync() } + .store(in: &cancellables) sync(item: service.item) } @@ -47,11 +47,9 @@ class WalletTokenBalanceViewModel { buttons = newButtons } } - } extension WalletTokenBalanceViewModel { - var playHapticPublisher: AnyPublisher { playHapticSubject.eraseToAnyPublisher() } @@ -85,10 +83,9 @@ extension WalletTokenBalanceViewModel { playHapticSubject.send() } - func onTapReceive() { switch service.element { - case .wallet(let wallet): + case let .wallet(wallet): if wallet.account.backedUp || service.isCloudBackedUp() { openReceiveSubject.send(wallet) } else { @@ -127,11 +124,9 @@ extension WalletTokenBalanceViewModel { openSyncErrorSubject.send((wallet, error)) } - } extension WalletTokenBalanceViewModel { - struct BalanceCustomStateViewItem { let title: String let amountValue: (text: String?, dimmed: Bool)? @@ -152,5 +147,4 @@ extension WalletTokenBalanceViewModel { let descriptionValue: (text: String?, dimmed: Bool)? let customStates: [BalanceCustomStateViewItem] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenModule.swift index 978151ac08..7694a8ef70 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenModule.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import MarketKit +import ThemeKit +import UIKit struct WalletTokenModule { - static func viewController(element: WalletModule.Element) -> UIViewController? { let service = WalletTokenService(element: element) let viewModel = WalletTokenViewModel(service: service) @@ -11,8 +10,8 @@ struct WalletTokenModule { let dataSourceChain = DataSourceChain() let viewController = WalletTokenViewController( - viewModel: viewModel, - dataSource: dataSourceChain + viewModel: viewModel, + dataSource: dataSourceChain ) guard let tokenBalanceDataSource = WalletTokenBalanceModule.dataSource(element: element) else { @@ -29,5 +28,4 @@ struct WalletTokenModule { return viewController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenService.swift index 1feea5eac1..52efaedbe0 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenService.swift @@ -1,6 +1,6 @@ +import Combine import Foundation import MarketKit -import Combine class WalletTokenService { private let element: WalletModule.Element @@ -8,11 +8,9 @@ class WalletTokenService { init(element: WalletModule.Element) { self.element = element } - } extension WalletTokenService { - var coinName: String { element.name } @@ -20,5 +18,4 @@ extension WalletTokenService { var badge: String? { element.wallet?.badge } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenViewModel.swift index ac402ffb29..ebebc7322c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Token/WalletTokenViewModel.swift @@ -8,11 +8,9 @@ class WalletTokenViewModel { init(service: WalletTokenService) { self.service = service } - } extension WalletTokenViewModel { - var title: String { var title = service.coinName if let badge = service.badge { @@ -20,5 +18,4 @@ extension WalletTokenViewModel { } return title } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/NoAccountWalletTokenListService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/NoAccountWalletTokenListService.swift index c9086ea28e..2fafa32a85 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/NoAccountWalletTokenListService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/NoAccountWalletTokenListService.swift @@ -19,11 +19,9 @@ class NoAccountWalletTokenListService: IWalletTokenListService { self.reachabilityManager = reachabilityManager self.balancePrimaryValueManager = balancePrimaryValueManager } - } extension NoAccountWalletTokenListService { - var isReachable: Bool { reachabilityManager.isReachable } @@ -40,8 +38,7 @@ extension NoAccountWalletTokenListService { .never() } - func item(element: WalletModule.Element) -> WalletTokenListService.Item? { + func item(element _: WalletModule.Element) -> WalletTokenListService.Item? { nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenCell.swift index b271d64adb..f3f6458b7b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class WalletTokenCell: BaseSelectableThemeCell { static let height = BalanceTopView.height @@ -17,11 +17,12 @@ class WalletTokenCell: BaseSelectableThemeCell { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } - func bind(viewItem: BalanceViewItem, animated: Bool = false, duration: TimeInterval = 0.2, onTapError: (() -> ())?) { + func bind(viewItem: BalanceViewItem, animated: Bool = false, duration: TimeInterval = 0.2, onTapError: (() -> Void)?) { topView.bind(viewItem: viewItem.topViewItem, onTapError: onTapError) topView.layoutIfNeeded() @@ -31,5 +32,4 @@ class WalletTokenCell: BaseSelectableThemeCell { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift index 81a02882c0..836c33d71c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift @@ -1,13 +1,13 @@ import Combine -import UIKit -import DeepDiff -import RxSwift -import RxCocoa import ComponentKit +import DeepDiff import HUD import MarketKit +import RxCocoa +import RxSwift import SectionsTableView import ThemeKit +import UIKit class WalletTokenListDataSource: NSObject { private let animationDuration: TimeInterval = 0.2 @@ -20,7 +20,7 @@ class WalletTokenListDataSource: NSObject { private var customCell: CustomCell = .none private var isLoaded = false - var onSelectWallet: ((Wallet) -> ())? + var onSelectWallet: ((Wallet) -> Void)? weak var viewController: UIViewController? private weak var tableView: UITableView? @@ -30,7 +30,8 @@ class WalletTokenListDataSource: NSObject { self.viewModel = viewModel } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -41,14 +42,14 @@ class WalletTokenListDataSource: NSObject { private func sync(state: WalletTokenListViewModel.State) { switch state { case .loading: customCell = .spinner - case .list(let viewItems): customCell = viewItems.isEmpty ? .noResults : .none + case let .list(viewItems): customCell = viewItems.isEmpty ? .noResults : .none case .empty, .noAccount: customCell = .empty case .syncFailed: customCell = .failed case .invalidApiKey: customCell = .invalidApiKey } switch state { - case .list(let viewItems): + case let .list(viewItems): viewController?.navigationItem.searchController?.searchBar.isHidden = false if isLoaded { handle(newViewItems: viewItems) @@ -85,10 +86,10 @@ class WalletTokenListDataSource: NSObject { for change in changes { switch change { - case .move(let move): + case let .move(move): updateIndexes.insert(move.fromIndex) updateIndexes.insert(move.toIndex) - case .replace(let replace): + case let .replace(replace): updateIndexes.insert(replace.index) default: () } @@ -121,12 +122,12 @@ class WalletTokenListDataSource: NSObject { cell.set(backgroundStyle: .transparent, isFirst: hideTopSeparator, isLast: index == viewItems.count - 1) cell.bind( - viewItem: viewItem, - animated: animated, - duration: animationDuration, - onTapError: { [weak self] in - self?.viewModel.onTapFailedIcon(element: viewItem.element) - } + viewItem: viewItem, + animated: animated, + duration: animationDuration, + onTapError: { [weak self] in + self?.viewModel.onTapFailedIcon(element: viewItem.element) + } ) } @@ -144,11 +145,9 @@ class WalletTokenListDataSource: NSObject { controller.addAction(UIAlertAction(title: "button.ok".localized, style: .default)) controller.show() } - } extension WalletTokenListDataSource: ISectionDataSource { - func prepare(tableView: UITableView) { self.tableView = tableView @@ -160,9 +159,9 @@ extension WalletTokenListDataSource: ISectionDataSource { // setup filter for search results if viewController has search if let viewController = viewController as? ThemeSearchViewController { viewController.$filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } + .store(in: &cancellables) } subscribe(disposeBag, viewModel.noConnectionErrorSignal) { HudHelper.instance.show(banner: .noInternet) } @@ -171,22 +170,22 @@ extension WalletTokenListDataSource: ISectionDataSource { subscribe(disposeBag, viewModel.openSyncErrorSignal) { [weak self] in self?.openSyncError(wallet: $0, error: $1) } viewModel.$state - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.sync(state: $0) - } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in + self?.sync(state: $0) + } + .store(in: &cancellables) sync(state: viewModel.state) isLoaded = true } - func numberOfSections(in tableView: UITableView) -> Int { + func numberOfSections(in _: UITableView) -> Int { (viewItems.isEmpty ? 0 : 1) + 1 } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { if viewItems.isEmpty { return 1 } else { @@ -215,7 +214,6 @@ extension WalletTokenListDataSource: ISectionDataSource { case 0: return tableView.dequeueReusableCell(withIdentifier: String(describing: WalletTokenCell.self), for: originalIndexPath) default: return tableView.dequeueReusableCell(withIdentifier: String(describing: EmptyCell.self), for: originalIndexPath) } - } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { @@ -244,10 +242,10 @@ extension WalletTokenListDataSource: ISectionDataSource { cell.text = "sync_error".localized cell.removeAllButtons() cell.addPrimaryButton( - style: .yellow, - title: "button.retry".localized, - target: self, - action: #selector(onTapRetry) + style: .yellow, + title: "button.retry".localized, + target: self, + action: #selector(onTapRetry) ) } case .invalidApiKey: @@ -291,11 +289,9 @@ extension WalletTokenListDataSource: ISectionDataSource { viewModel.didSelect(item: viewItems[indexPath.row]) } } - } extension WalletTokenListDataSource { - enum CustomCell { case none case empty @@ -311,5 +307,4 @@ extension WalletTokenListDataSource { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift index 5759aef000..f2efc74edd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift @@ -1,9 +1,9 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import HsToolKit +import Foundation import HsExtensions +import HsToolKit +import RxRelay +import RxSwift class WalletTokenListService: IWalletTokenListService { private let elementService: IWalletElementService @@ -23,7 +23,7 @@ class WalletTokenListService: IWalletTokenListService { private var internalState: State = .loading { didSet { switch internalState { - case .loaded(let items): + case let .loaded(items): state = .loaded(items: items) default: state = internalState @@ -36,6 +36,7 @@ class WalletTokenListService: IWalletTokenListService { stateUpdatedSubject.send(state) } } + let stateUpdatedSubject = PassthroughSubject() private let itemUpdatedRelay = PublishRelay() @@ -45,8 +46,8 @@ class WalletTokenListService: IWalletTokenListService { init(elementService: IWalletElementService, coinPriceService: WalletCoinPriceService, cacheManager: EnabledWalletCacheManager, reachabilityManager: IReachabilityManager, balancePrimaryValueManager: BalancePrimaryValueManager, balanceHiddenManager: BalanceHiddenManager, - appManager: IAppManager, feeCoinProvider: FeeCoinProvider, account: Account - ) { + appManager: IAppManager, feeCoinProvider: FeeCoinProvider, account: Account) + { self.elementService = elementService self.coinPriceService = coinPriceService self.cacheManager = cacheManager @@ -71,52 +72,44 @@ class WalletTokenListService: IWalletTokenListService { switch elementState { case .loading: internalState = .loading - case .loaded(let elements): + case let .loaded(elements): let cacheContainer = cacheManager.cacheContainer(accountId: account.id) - let priceItemMap = coinPriceService.itemMap(coinUids: elements.compactMap { - $0.priceCoinUid - }) + let priceItemMap = coinPriceService.itemMap(coinUids: elements.compactMap(\.priceCoinUid)) let items: [Item] = elements.filter { elementFilter?($0) ?? true } - .map { element in - let item = Item( - element: element, - isMainNet: elementService.isMainNet(element: element) ?? fallbackIsMainNet, - balanceData: elementService.balanceData(element: element) ?? _cachedBalanceData(element: element, cacheContainer: cacheContainer) ?? fallbackBalanceData, - state: elementService.state(element: element) ?? fallbackAdapterState - ) - - if let priceCoinUid = element.priceCoinUid { - item.priceItem = priceItemMap[priceCoinUid] - } - - return item + .map { element in + let item = Item( + element: element, + isMainNet: elementService.isMainNet(element: element) ?? fallbackIsMainNet, + balanceData: elementService.balanceData(element: element) ?? _cachedBalanceData(element: element, cacheContainer: cacheContainer) ?? fallbackBalanceData, + state: elementService.state(element: element) ?? fallbackAdapterState + ) + + if let priceCoinUid = element.priceCoinUid { + item.priceItem = priceItemMap[priceCoinUid] } + return item + } + internalState = .loaded(items: sorter.sort(items: items, sortType: .balance)) - let coinUids = Set(elements.compactMap { - $0.priceCoinUid - }) - let feeCoinUids = Set(elements.compactMap { - $0.wallet - } - .compactMap { - feeCoinProvider.feeToken(token: $0.token) - } - .map { - $0.coin.uid - }) + let coinUids = Set(elements.compactMap(\.priceCoinUid)) + let feeCoinUids = Set(elements.compactMap(\.wallet) + .compactMap { + feeCoinProvider.feeToken(token: $0.token) + } + .map(\.coin.uid)) coinPriceService.set(coinUids: coinUids.union(feeCoinUids)) - case .failed(let reason): + case let .failed(reason): internalState = .failed(reason: reason) } } private func _cachedBalanceData(element: WalletModule.Element, cacheContainer: EnabledWalletCacheManager.CacheContainer?) -> BalanceData? { switch element { - case .wallet(let wallet): return cacheContainer?.balanceData(wallet: wallet) + case let .wallet(wallet): return cacheContainer?.balanceData(wallet: wallet) default: return nil } } @@ -162,11 +155,9 @@ class WalletTokenListService: IWalletTokenListService { private var fallbackAdapterState: AdapterState { .syncing(progress: nil, lastBlockDate: nil) } - } extension WalletTokenListService: IWalletElementServiceDelegate { - func didUpdate(elementState: WalletModule.ElementState, elementService: IWalletElementService) { queue.async { self.sync(elementState: elementState, elementService: elementService) @@ -175,7 +166,7 @@ extension WalletTokenListService: IWalletElementServiceDelegate { func didUpdateElements(elementService: IWalletElementService) { queue.async { - guard case .loaded(let items) = self.internalState else { + guard case let .loaded(items) = self.internalState else { return } @@ -203,7 +194,7 @@ extension WalletTokenListService: IWalletElementServiceDelegate { func didUpdate(isMainNet: Bool, element: WalletModule.Element) { queue.async { - guard case .loaded(let items) = self.internalState, let item = self._item(element: element, items: items) else { + guard case let .loaded(items) = self.internalState, let item = self._item(element: element, items: items) else { return } @@ -215,13 +206,13 @@ extension WalletTokenListService: IWalletElementServiceDelegate { func didUpdate(balanceData: BalanceData, element: WalletModule.Element) { queue.async { - guard case .loaded(let items) = self.internalState, let item = self._item(element: element, items: items) else { + guard case let .loaded(items) = self.internalState, let item = self._item(element: element, items: items) else { return } item.balanceData = balanceData - if items.allSatisfy({ $0.state.isSynced }) { + if items.allSatisfy(\.state.isSynced) { self.internalState = .loaded(items: self._sorted(items: items)) } else { self.itemUpdatedRelay.accept(item) @@ -235,24 +226,22 @@ extension WalletTokenListService: IWalletElementServiceDelegate { func didUpdate(state: AdapterState, element: WalletModule.Element) { queue.async { - guard case .loaded(let items) = self.internalState, let item = self._item(element: element, items: items) else { + guard case let .loaded(items) = self.internalState, let item = self._item(element: element, items: items) else { return } item.state = state - if items.allSatisfy({ $0.state.isSynced }) { + if items.allSatisfy(\.state.isSynced) { self.internalState = .loaded(items: self._sorted(items: items)) } else { self.itemUpdatedRelay.accept(item) } } } - } extension WalletTokenListService: IWalletCoinPriceServiceDelegate { - private func _handleUpdated(priceItemMap: [String: WalletCoinPriceService.Item], items: [Item]) { for item in items { if let priceCoinUid = item.element.priceCoinUid { @@ -265,31 +254,27 @@ extension WalletTokenListService: IWalletCoinPriceServiceDelegate { func didUpdateBaseCurrency() { queue.async { - guard case .loaded(let items) = self.internalState else { + guard case let .loaded(items) = self.internalState else { return } - let coinUids = Array(Set(items.compactMap { - $0.element.priceCoinUid - })) + let coinUids = Array(Set(items.compactMap(\.element.priceCoinUid))) self._handleUpdated(priceItemMap: self.coinPriceService.itemMap(coinUids: coinUids), items: items) } } func didUpdate(itemsMap: [String: WalletCoinPriceService.Item]) { queue.async { - guard case .loaded(let items) = self.internalState else { + guard case let .loaded(items) = self.internalState else { return } self._handleUpdated(priceItemMap: itemsMap, items: items) } } - } extension WalletTokenListService { - var itemUpdatedObservable: Observable { itemUpdatedRelay.asObservable() } @@ -300,18 +285,16 @@ extension WalletTokenListService { func item(element: WalletModule.Element) -> Item? { queue.sync { - guard case .loaded(let items) = internalState else { + guard case let .loaded(items) = internalState else { return nil } return _item(element: element, items: items) } } - } extension WalletTokenListService { - enum State: CustomStringConvertible { case noAccount case loading @@ -322,7 +305,7 @@ extension WalletTokenListService { switch self { case .noAccount: return "noAccount" case .loading: return "loading" - case .loaded(let items): return "loaded: \(items.count) items" + case let .loaded(items): return "loaded: \(items.count) items" case .failed: return "failed" } } @@ -342,5 +325,4 @@ extension WalletTokenListService { self.state = state } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewController.swift index 32cec63e69..8826a19f21 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewController.swift @@ -1,13 +1,13 @@ import Combine -import UIKit -import DeepDiff -import RxSwift -import RxCocoa import ComponentKit +import DeepDiff import HUD import MarketKit +import RxCocoa +import RxSwift import SectionsTableView import ThemeKit +import UIKit class WalletTokenListViewController: ThemeSearchViewController { private let viewModel: WalletTokenListViewModel @@ -25,7 +25,8 @@ class WalletTokenListViewController: ThemeSearchViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -68,5 +69,4 @@ class WalletTokenListViewController: ThemeSearchViewController { @objc func onTapClose() { dismiss(animated: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewItemFactory.swift index c9896c9b29..0daf132b3b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewItemFactory.swift @@ -1,6 +1,6 @@ +import EvmKit import Foundation import MarketKit -import EvmKit class WalletTokenListViewItemFactory { private let minimumProgress = 10 @@ -11,17 +11,17 @@ class WalletTokenListViewItemFactory { let sendEnabled = state.spendAllowed(beforeSync: item.balanceData.sendBeforeSync) return BalanceTopViewItem( - isMainNet: item.isMainNet, - iconUrlString: iconUrlString(coin: item.element.coin, state: state), - placeholderIconName: item.element.wallet?.token.placeholderImageName ?? "placeholder_circle_32", - name: item.element.name, - blockchainBadge: item.element.wallet?.badge, - syncSpinnerProgress: syncSpinnerProgress(state: state), - indefiniteSearchCircle: indefiniteSearchCircle(state: state), - failedImageViewVisible: failedImageViewVisible(state: state), - sendEnabled: sendEnabled, - primaryValue: primaryValue(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden), - secondaryInfo: secondaryInfo(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) + isMainNet: item.isMainNet, + iconUrlString: iconUrlString(coin: item.element.coin, state: state), + placeholderIconName: item.element.wallet?.token.placeholderImageName ?? "placeholder_circle_32", + name: item.element.name, + blockchainBadge: item.element.wallet?.badge, + syncSpinnerProgress: syncSpinnerProgress(state: state), + indefiniteSearchCircle: indefiniteSearchCircle(state: state), + failedImageViewVisible: failedImageViewVisible(state: state), + sendEnabled: sendEnabled, + primaryValue: primaryValue(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden), + secondaryInfo: secondaryInfo(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) ) } @@ -32,15 +32,15 @@ class WalletTokenListViewItemFactory { return .customSyncing(main: main, secondary: secondary) } else if case .stopped = item.state { return .amount(viewItem: BalanceSecondaryAmountViewItem( - descriptionValue: (text: "balance.stopped".localized, dimmed: false), - secondaryValue: nil, - diff: nil + descriptionValue: (text: "balance.stopped".localized, dimmed: false), + secondaryValue: nil, + diff: nil )) } else { return .amount(viewItem: BalanceSecondaryAmountViewItem( - descriptionValue: (text: item.element.coin?.name, dimmed: false), - secondaryValue: secondaryValue(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden, expanded: true), - diff: nil + descriptionValue: (text: item.element.coin?.name, dimmed: false), + secondaryValue: secondaryValue(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden, expanded: true), + diff: nil )) } } @@ -55,7 +55,7 @@ class WalletTokenListViewItemFactory { private func syncSpinnerProgress(state: AdapterState) -> Int? { switch state { case let .syncing(progress, _): - if let progress = progress { + if let progress { return max(minimumProgress, progress) } else { return infiniteProgress @@ -87,7 +87,7 @@ class WalletTokenListViewItemFactory { } } - private func secondaryValue(item: WalletTokenListService.Item, balancePrimaryValue: BalancePrimaryValue, balanceHidden: Bool, expanded: Bool) -> (text: String?, dimmed: Bool) { + private func secondaryValue(item: WalletTokenListService.Item, balancePrimaryValue: BalancePrimaryValue, balanceHidden: Bool, expanded _: Bool) -> (text: String?, dimmed: Bool) { switch balancePrimaryValue { case .coin: return currencyValue(value: item.balanceData.balanceTotal, state: item.state, priceItem: item.priceItem, balanceHidden: balanceHidden) case .currency: return coinValue(value: item.balanceData.balanceTotal, decimalCount: item.element.decimals, state: item.state, balanceHidden: balanceHidden) @@ -96,13 +96,13 @@ class WalletTokenListViewItemFactory { private func coinValue(value: Decimal, decimalCount: Int, symbol: String? = nil, state: AdapterState, balanceHidden: Bool) -> (text: String?, dimmed: Bool) { ( - text: balanceHidden ? BalanceHiddenManager.placeholder : ValueFormatter.instance.formatShort(value: value, decimalCount: decimalCount, symbol: symbol), - dimmed: state != .synced + text: balanceHidden ? BalanceHiddenManager.placeholder : ValueFormatter.instance.formatShort(value: value, decimalCount: decimalCount, symbol: symbol), + dimmed: state != .synced ) } private func currencyValue(value: Decimal, state: AdapterState, priceItem: WalletCoinPriceService.Item?, balanceHidden: Bool) -> (text: String?, dimmed: Bool) { - guard let priceItem = priceItem else { + guard let priceItem else { return (text: "---", dimmed: true) } @@ -110,20 +110,17 @@ class WalletTokenListViewItemFactory { let currencyValue = CurrencyValue(currency: price.currency, value: value * price.value) return ( - text: balanceHidden ? BalanceHiddenManager.placeholder : ValueFormatter.instance.formatShort(currencyValue: currencyValue), - dimmed: state != .synced || priceItem.expired + text: balanceHidden ? BalanceHiddenManager.placeholder : ValueFormatter.instance.formatShort(currencyValue: currencyValue), + dimmed: state != .synced || priceItem.expired ) } - } extension WalletTokenListViewItemFactory { - func viewItem(item: WalletTokenListService.Item, balancePrimaryValue: BalancePrimaryValue, balanceHidden: Bool) -> BalanceViewItem { BalanceViewItem( - element: item.element, - topViewItem: topViewItem(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) + element: item.element, + topViewItem: topViewItem(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift index f2d18ab295..fc7b8d06c3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift @@ -1,10 +1,10 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import RxCocoa -import MarketKit +import Foundation import HsExtensions +import MarketKit +import RxCocoa +import RxRelay +import RxSwift protocol IWalletTokenListService { var state: WalletTokenListService.State { get set } @@ -30,8 +30,8 @@ class WalletTokenListViewModel { let emptyText: String private let showWarningRelay = BehaviorRelay(value: nil) - private let noConnectionErrorRelay = PublishRelay<()>() - private let showSyncingRelay = PublishRelay<()>() + private let noConnectionErrorRelay = PublishRelay() + private let showSyncingRelay = PublishRelay() private let selectWalletRelay = PublishRelay() private let openSyncErrorRelay = PublishRelay<(Wallet, Error)>() @@ -52,8 +52,8 @@ class WalletTokenListViewModel { subscribe(disposeBag, service.balanceHiddenObservable) { [weak self] _ in self?.onUpdate() } service.stateUpdatedPublisher - .sink { [weak self] in self?.sync(serviceState: $0) } - .store(in: &cancellables) + .sink { [weak self] in self?.sync(serviceState: $0) } + .store(in: &cancellables) _sync(serviceState: service.state) } @@ -64,17 +64,17 @@ class WalletTokenListViewModel { } } - private func _sync(serviceState: WalletTokenListService.State) { + private func _sync(serviceState _: WalletTokenListService.State) { switch service.state { case .noAccount: state = .noAccount case .loading: state = .loading - case .loaded(let items): + case let .loaded(items): if items.isEmpty { state = .empty } else { state = .list(viewItems: items.compactMap { _viewItem(item: $0) }) } - case .failed(let reason): + case let .failed(reason): switch reason { case .syncFailed: state = .syncFailed case .invalidApiKey: state = .invalidApiKey @@ -88,7 +88,7 @@ class WalletTokenListViewModel { private func syncUpdated(item: WalletTokenListService.Item) { queue.async { - guard case .list(var viewItems) = self.state else { + guard case var .list(viewItems) = self.state else { return } @@ -104,15 +104,15 @@ class WalletTokenListViewModel { } private func _viewItem(item: WalletTokenListService.Item) -> BalanceViewItem? { - if let filter = filter, !filter.isEmpty { + if let filter, !filter.isEmpty { if !(item.element.name.localizedCaseInsensitiveContains(filter) || (item.element.coin?.name.localizedCaseInsensitiveContains(filter) ?? false)) { return nil } } return factory.viewItem( - item: item, - balancePrimaryValue: service.balancePrimaryValue, - balanceHidden: service.balanceHidden + item: item, + balancePrimaryValue: service.balancePrimaryValue, + balanceHidden: service.balanceHidden ) } @@ -121,20 +121,18 @@ class WalletTokenListViewModel { sync(serviceState: service.state) } - } extension WalletTokenListViewModel { - var showWarningDriver: Driver { showWarningRelay.asDriver() } - var noConnectionErrorSignal: Signal<()> { + var noConnectionErrorSignal: Signal { noConnectionErrorRelay.asSignal() } - var showSyncingSignal: Signal<()> { + var showSyncingSignal: Signal { showSyncingRelay.asSignal() } @@ -186,11 +184,9 @@ extension WalletTokenListViewModel { self?.set(filter: filter) } } - } extension WalletTokenListViewModel { - enum State: CustomStringConvertible { case list(viewItems: [BalanceViewItem]) case noAccount @@ -201,7 +197,7 @@ extension WalletTokenListViewModel { var description: String { switch self { - case .list(let viewItems): return "list: \(viewItems.count) view items" + case let .list(viewItems): return "list: \(viewItems.count) view items" case .noAccount: return "noAccount" case .empty: return "empty" case .loading: return "loading" @@ -210,5 +206,4 @@ extension WalletTokenListViewModel { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsCell.swift index 9fcfdf0b16..baf83b33b5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsCell.swift @@ -1,13 +1,13 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class BalanceButtonsCell: UITableViewCell { static let height = BalanceButtonsView.height private let buttonsView = BalanceButtonsView() - var actions: [WalletModule.Button: () -> ()] = [:] + var actions: [WalletModule.Button: () -> Void] = [:] override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -22,20 +22,20 @@ class BalanceButtonsCell: UITableViewCell { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } func bind(buttons: [WalletModule.Button: ButtonState]) { buttonsView.bind( - buttons: buttons, - sendAction: actions[.send], - withdrawAction: actions[.withdraw], - receiveAction: actions[.receive], - depositAction: actions[.deposit], - swapAction: actions[.swap], - chartAction: actions[.chart] + buttons: buttons, + sendAction: actions[.send], + withdrawAction: actions[.withdraw], + receiveAction: actions[.receive], + depositAction: actions[.deposit], + swapAction: actions[.swap], + chartAction: actions[.chart] ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsView.swift index f9e40051b2..dc7e97bb66 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceButtonsView.swift @@ -1,8 +1,8 @@ -import UIKit -import UIExtensions +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIExtensions +import UIKit class BalanceButtonsView: UIView { public static let height: CGFloat = 70 @@ -21,12 +21,12 @@ class BalanceButtonsView: UIView { private let chartButtonWrapper = UIControl() private let chartButton = PrimaryCircleButton() - private var onTapSend: (() -> ())? - private var onTapWithdraw: (() -> ())? - private var onTapReceive: (() -> ())? - private var onTapDeposit: (() -> ())? - private var onTapSwap: (() -> ())? - private var onTapChart: (() -> ())? + private var onTapSend: (() -> Void)? + private var onTapWithdraw: (() -> Void)? + private var onTapReceive: (() -> Void)? + private var onTapDeposit: (() -> Void)? + private var onTapSwap: (() -> Void)? + private var onTapChart: (() -> Void)? init() { super.init(frame: .zero) @@ -122,11 +122,12 @@ class BalanceButtonsView: UIView { chartButton.addTarget(self, action: #selector(onChart), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } - func bind(buttons: [WalletModule.Button: ButtonState], sendAction: (() -> ())?, withdrawAction: (() -> ())?, receiveAction: (() -> ())?, depositAction: (() -> ())?, swapAction: (() -> ())?, chartAction: (() -> ())?) { + func bind(buttons: [WalletModule.Button: ButtonState], sendAction: (() -> Void)?, withdrawAction: (() -> Void)?, receiveAction: (() -> Void)?, depositAction: (() -> Void)?, swapAction: (() -> Void)?, chartAction: (() -> Void)?) { sendButton.isEnabled = buttons[.send] == .enabled withdrawButton.isEnabled = buttons[.withdraw] == .enabled receiveButton.isEnabled = buttons[.receive] == .enabled @@ -176,5 +177,4 @@ class BalanceButtonsView: UIView { @objc private func onChart() { onTapChart?() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCell.swift index 2edced546b..a02cc20e55 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class BalanceCell: UITableViewCell { private static let margins = UIEdgeInsets(top: .margin8, left: .margin16, bottom: 0, right: .margin16) @@ -28,17 +28,17 @@ class BalanceCell: UITableViewCell { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } - func bind(viewItem: BalanceViewItem, onTapError: (() -> ())?) { + func bind(viewItem: BalanceViewItem, onTapError: (() -> Void)?) { topView.bind(viewItem: viewItem.topViewItem, onTapError: onTapError) topView.layoutIfNeeded() } static func height() -> CGFloat { - return BalanceTopView.height + margins.height + BalanceTopView.height + margins.height } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCoinIconHolder.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCoinIconHolder.swift index f2adf1bec9..59b19aefbd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCoinIconHolder.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceCoinIconHolder.swift @@ -1,20 +1,20 @@ -import UIKit -import ThemeKit -import HUD import ComponentKit +import HUD +import ThemeKit +import UIKit class BalanceCoinIconHolder: UIView { private let coinIconImageView = UIImageView() private let syncSpinner = HUDProgressView( - progress: 0, - strokeLineWidth: 2, - radius: 19, - strokeColor: .themeGray, - duration: 2 + progress: 0, + strokeLineWidth: 2, + radius: 19, + strokeColor: .themeGray, + duration: 2 ) private let failedButton = UIButton() - private var onTapError: (() -> ())? + private var onTapError: (() -> Void)? init() { super.init(frame: .zero) @@ -40,7 +40,8 @@ class BalanceCoinIconHolder: UIView { failedButton.addTarget(self, action: #selector(onTapErrorButton), for: .touchUpInside) } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -48,17 +49,17 @@ class BalanceCoinIconHolder: UIView { onTapError?() } - func bind(iconUrlString: String?, placeholderIconName: String, spinnerProgress: Int?, indefiniteSearchCircle: Bool, failViewVisible: Bool, onTapError: (() -> ())?) { + func bind(iconUrlString: String?, placeholderIconName: String, spinnerProgress: Int?, indefiniteSearchCircle: Bool, failViewVisible: Bool, onTapError: (() -> Void)?) { self.onTapError = onTapError coinIconImageView.isHidden = iconUrlString == nil - if let iconUrlString = iconUrlString { + if let iconUrlString { coinIconImageView.setImage(withUrlString: iconUrlString, placeholder: UIImage(named: placeholderIconName)) } else { coinIconImageView.image = nil } - if let spinnerProgress = spinnerProgress { + if let spinnerProgress { syncSpinner.set(progress: Float(spinnerProgress) / 100) syncSpinner.set(strokeColor: .themeGray) syncSpinner.isHidden = false @@ -75,5 +76,4 @@ class BalanceCoinIconHolder: UIView { failedButton.isHidden = !failViewVisible } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceTopView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceTopView.swift index ad6fb0036b..9fcdee0c32 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceTopView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/BalanceTopView.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class BalanceTopView: UIView { static let height: CGFloat = 62 @@ -96,18 +96,18 @@ class BalanceTopView: UIView { bottomRightLabel.font = .subhead2 } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - func bind(viewItem: BalanceTopViewItem, onTapError: (() -> ())?) { + func bind(viewItem: BalanceTopViewItem, onTapError: (() -> Void)?) { coinIconView.bind( - iconUrlString: viewItem.iconUrlString, - placeholderIconName: viewItem.placeholderIconName, - spinnerProgress: viewItem.syncSpinnerProgress, - indefiniteSearchCircle: viewItem.indefiniteSearchCircle, - failViewVisible: viewItem.failedImageViewVisible, - onTapError: onTapError + iconUrlString: viewItem.iconUrlString, + placeholderIconName: viewItem.placeholderIconName, + spinnerProgress: viewItem.syncSpinnerProgress, + indefiniteSearchCircle: viewItem.indefiniteSearchCircle, + failViewVisible: viewItem.failedImageViewVisible, + onTapError: onTapError ) testnetImageView.isHidden = viewItem.isMainNet @@ -157,14 +157,14 @@ class BalanceTopView: UIView { case let .syncing(progress, syncedUntil): diffLabel.isHidden = true - if let progress = progress { + if let progress { bottomLeftLabel.text = "balance.syncing_percent".localized("\(progress)%") } else { bottomLeftLabel.text = "balance.syncing".localized } bottomLeftLabel.textColor = .themeGray - if let syncedUntil = syncedUntil { + if let syncedUntil { bottomRightLabel.isHidden = false bottomRightLabel.text = "balance.synced_through".localized(syncedUntil) bottomRightLabel.textColor = .themeGray @@ -176,7 +176,7 @@ class BalanceTopView: UIView { bottomLeftLabel.text = left bottomLeftLabel.textColor = .themeGray - if let right = right { + if let right { bottomRightLabel.isHidden = false bottomRightLabel.text = right bottomRightLabel.textColor = .themeGray @@ -185,5 +185,4 @@ class BalanceTopView: UIView { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/WalletHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/WalletHeaderCell.swift index 115c153c41..fe6d2e97fa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/WalletHeaderCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/Views/WalletHeaderCell.swift @@ -1,13 +1,13 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class WalletHeaderCell: UITableViewCell { - internal var amountView = HeaderAmountView() - internal let buttonsView = BalanceButtonsView() + var amountView = HeaderAmountView() + let buttonsView = BalanceButtonsView() - var actions: [WalletModule.Button: () -> ()] = [:] + var actions: [WalletModule.Button: () -> Void] = [:] override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -29,16 +29,17 @@ class WalletHeaderCell: UITableViewCell { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } - var onTapAmount: (() -> ())? { + var onTapAmount: (() -> Void)? { get { amountView.onTapAmount } set { amountView.onTapAmount = newValue } } - var onTapConvertedAmount: (() -> ())? { + var onTapConvertedAmount: (() -> Void)? { get { amountView.onTapConvertedAmount } set { amountView.onTapConvertedAmount = newValue } } @@ -47,20 +48,18 @@ class WalletHeaderCell: UITableViewCell { amountView.set(amountText: viewItem.amount, expired: viewItem.amountExpired) amountView.set(convertedAmountText: viewItem.convertedValue, expired: viewItem.convertedValueExpired) buttonsView.bind( - buttons: viewItem.buttons, - sendAction: actions[.send], - withdrawAction: actions[.withdraw], - receiveAction: actions[.receive], - depositAction: actions[.deposit], - swapAction: actions[.swap], - chartAction: actions[.chart] + buttons: viewItem.buttons, + sendAction: actions[.send], + withdrawAction: actions[.withdraw], + receiveAction: actions[.receive], + depositAction: actions[.deposit], + swapAction: actions[.swap], + chartAction: actions[.chart] ) } - } extension WalletHeaderCell { - static func height(viewItem: WalletModule.HeaderViewItem?) -> CGFloat { guard let viewItem else { return HeaderAmountView.height @@ -68,9 +67,8 @@ extension WalletHeaderCell { var buttonsHidden = viewItem.buttons.isEmpty if !viewItem.buttons.isEmpty { - buttonsHidden = viewItem.buttons.allSatisfy { key, value in value == .hidden } + buttonsHidden = viewItem.buttons.allSatisfy { _, value in value == .hidden } } return HeaderAmountView.height + (buttonsHidden ? 0 : BalanceButtonsView.height) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletAdapterService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletAdapterService.swift index e3ae4f8d08..576ed3ddb3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletAdapterService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletAdapterService.swift @@ -60,7 +60,6 @@ class WalletAdapterService { } extension WalletAdapterService { - func isMainNet(wallet: Wallet) -> Bool? { queue.sync { adapterMap[wallet]?.isMainNet } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletBlockchainElementService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletBlockchainElementService.swift index d3db8a10f6..6798e00e78 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletBlockchainElementService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletBlockchainElementService.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import MarketKit +import RxSwift class WalletBlockchainElementService { private let account: Account @@ -45,11 +45,9 @@ class WalletBlockchainElementService { private func handleUpdated(wallets: [Wallet]) { delegate?.didUpdate(elementState: .loaded(elements: filtered(wallets).map { .wallet(wallet: $0) }), elementService: self) } - } extension WalletBlockchainElementService: IWalletElementService { - var state: WalletModule.ElementState { .loaded(elements: filtered(walletManager.activeWallets).map { .wallet(wallet: $0) }) } @@ -89,11 +87,9 @@ extension WalletBlockchainElementService: IWalletElementService { walletManager.delete(wallets: [wallet]) } - } extension WalletBlockchainElementService: IWalletAdapterServiceDelegate { - func didPrepareAdapters() { delegate?.didUpdateElements(elementService: self) } @@ -109,5 +105,4 @@ extension WalletBlockchainElementService: IWalletAdapterServiceDelegate { func didUpdate(state: AdapterState, wallet: Wallet) { delegate?.didUpdate(state: state, element: .wallet(wallet: wallet)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCexElementService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCexElementService.swift index 39b1ae553c..2f679fd0ad 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCexElementService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCexElementService.swift @@ -1,8 +1,8 @@ import Foundation -import RxSwift -import HsToolKit import HsExtensions +import HsToolKit import MarketKit +import RxSwift class WalletCexElementService { private let account: Account @@ -46,7 +46,7 @@ class WalletCexElementService { state = cexAssets.isEmpty ? .loading : .loaded(elements: elements) case .loaded: state = .loaded(elements: elements) - case .failed(let reason): + case let .failed(reason): switch reason { case .syncFailed: state = cexAssets.isEmpty ? .failed(reason: reason) : .loaded(elements: elements) case .invalidApiKey: state = .failed(reason: reason) @@ -76,12 +76,10 @@ class WalletCexElementService { } }.store(in: &tasks) } - } extension WalletCexElementService: IWalletElementService { - - func isMainNet(element: WalletModule.Element) -> Bool? { + func isMainNet(element _: WalletModule.Element) -> Bool? { true } @@ -93,9 +91,9 @@ extension WalletCexElementService: IWalletElementService { return VerifiedBalanceData(fullBalance: cexAsset.freeBalance + cexAsset.lockedBalance, available: cexAsset.freeBalance) } - func state(element: WalletModule.Element) -> AdapterState? { + func state(element _: WalletModule.Element) -> AdapterState? { switch internalState { - case .failed(let reason): return .notSynced(error: reason) + case let .failed(reason): return .notSynced(error: reason) default: return .synced } } @@ -104,18 +102,15 @@ extension WalletCexElementService: IWalletElementService { sync() } - func disable(element: WalletModule.Element) { + func disable(element _: WalletModule.Element) { // not supported } - } extension WalletCexElementService { - enum State { case loading case loaded case failed(reason: WalletModule.FailureReason) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCoinPriceService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCoinPriceService.swift index 8c23a078b6..7f84c3377a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCoinPriceService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletCoinPriceService.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation import MarketKit protocol IWalletCoinPriceServiceDelegate: AnyObject { @@ -29,10 +29,10 @@ class WalletCoinPriceService { currency = currencyManager.baseCurrency currencyManager.$baseCurrency - .sink { [weak self] currency in - self?.onUpdate(baseCurrency: currency) - } - .store(in: &cancellables) + .sink { [weak self] currency in + self?.onUpdate(baseCurrency: currency) + } + .store(in: &cancellables) } private func onUpdate(baseCurrency: Currency) { @@ -46,22 +46,22 @@ class WalletCoinPriceService { if !coinUids.isEmpty { marketKit.coinPriceMapPublisher(tag: tag, coinUids: Array(coinUids), currencyCode: currencyManager.baseCurrency.code) - .sink { [weak self] in - self?.onUpdate(coinPriceMap: $0) - } - .store(in: &coinPriceCancellables) + .sink { [weak self] in + self?.onUpdate(coinPriceMap: $0) + } + .store(in: &coinPriceCancellables) } if !feeCoinUids.isEmpty { marketKit.coinPriceMapPublisher(tag: "fee:\(tag)", coinUids: Array(feeCoinUids), currencyCode: currencyManager.baseCurrency.code) - .sink { _ in } - .store(in: &coinPriceCancellables) + .sink { _ in } + .store(in: &coinPriceCancellables) } if !conversionCoinUids.isEmpty { marketKit.coinPriceMapPublisher(tag: "conversion:\(tag)", coinUids: Array(conversionCoinUids), currencyCode: currencyManager.baseCurrency.code) - .sink { _ in } - .store(in: &coinPriceCancellables) + .sink { _ in } + .store(in: &coinPriceCancellables) } } @@ -74,18 +74,16 @@ class WalletCoinPriceService { let currency = currencyManager.baseCurrency return Item( - price: CurrencyValue(currency: currency, value: coinPrice.value), - diff: coinPrice.diff, - expired: coinPrice.expired + price: CurrencyValue(currency: currency, value: coinPrice.value), + diff: coinPrice.diff, + expired: coinPrice.expired ) } - } extension WalletCoinPriceService { - func set(coinUids: Set, feeCoinUids: Set = Set(), conversionCoinUids: Set = Set()) { - if self.coinUids == coinUids && self.feeCoinUids == feeCoinUids && self.conversionCoinUids == conversionCoinUids { + if self.coinUids == coinUids, self.feeCoinUids == feeCoinUids, self.conversionCoinUids == conversionCoinUids { return } @@ -109,15 +107,12 @@ extension WalletCoinPriceService { func refresh() { marketKit.refreshCoinPrices(currencyCode: currency.code) } - } extension WalletCoinPriceService { - struct Item { let price: CurrencyValue let diff: Decimal? let expired: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletElementServiceFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletElementServiceFactory.swift index 6f711f311f..17047295e5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletElementServiceFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletElementServiceFactory.swift @@ -16,16 +16,15 @@ struct WalletElementServiceFactory { case .mnemonic, .evmPrivateKey, .evmAddress, .tronAddress, .tonAddress, .hdExtendedKey: let adapterService = WalletAdapterService(account: account, adapterManager: adapterManager) let elementService = WalletBlockchainElementService( - account: account, - adapterService: adapterService, - walletManager: walletManager + account: account, + adapterService: adapterService, + walletManager: walletManager ) adapterService.delegate = elementService return elementService - case .cex(let cexAccount): + case let .cex(cexAccount): return WalletCexElementService(account: account, provider: cexAccount.assetProvider, cexAssetManager: cexAssetManager) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletService.swift index 0701523748..376a74f2b4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletService.swift @@ -1,9 +1,9 @@ -import Foundation import Combine -import RxSwift -import RxRelay -import HsToolKit +import Foundation import HsExtensions +import HsToolKit +import RxRelay +import RxSwift protocol IWalletElementService: AnyObject { var delegate: IWalletElementServiceDelegate? { get set } @@ -45,7 +45,7 @@ class WalletService { private var internalState: State = .loading { didSet { switch internalState { - case .loaded(let items): + case let .loaded(items): state = .loaded(items: items) default: state = internalState @@ -59,7 +59,7 @@ class WalletService { @PostPublished private(set) var totalItem: TotalItem? private let activeAccountRelay = PublishRelay() - private let accountsLostRelay = PublishRelay<()>() + private let accountsLostRelay = PublishRelay() private let itemUpdatedRelay = PublishRelay() private let sortTypeRelay = PublishRelay() @@ -71,15 +71,14 @@ class WalletService { } } - private let queue = DispatchQueue(label: "\(AppConfig.label).wallet-service", qos: .userInitiated) init(elementServiceFactory: WalletElementServiceFactory, coinPriceService: WalletCoinPriceService, accountManager: AccountManager, cacheManager: EnabledWalletCacheManager, accountRestoreWarningManager: AccountRestoreWarningManager, reachabilityManager: IReachabilityManager, balancePrimaryValueManager: BalancePrimaryValueManager, balanceHiddenManager: BalanceHiddenManager, balanceConversionManager: BalanceConversionManager, cloudAccountBackupManager: CloudBackupManager, rateAppManager: RateAppManager, appManager: IAppManager, feeCoinProvider: FeeCoinProvider, - userDefaultsStorage: UserDefaultsStorage - ) { + userDefaultsStorage: UserDefaultsStorage) + { self.elementServiceFactory = elementServiceFactory self.coinPriceService = coinPriceService self.accountManager = accountManager @@ -97,7 +96,7 @@ class WalletService { if let rawValue: String = userDefaultsStorage.value(for: keySortType), let sortType = WalletModule.SortType(rawValue: rawValue) { self.sortType = sortType } else if let rawValue: Int = userDefaultsStorage.value(for: "balance_sort_key"), rawValue < WalletModule.SortType.allCases.count { - // todo: temp solution for restoring from version 0.22 + // TODO: temp solution for restoring from version 0.22 sortType = WalletModule.SortType.allCases[rawValue] } else { sortType = .balance @@ -149,16 +148,16 @@ class WalletService { switch elementState { case .loading: internalState = .loading - case .loaded(let elements): + case let .loaded(elements): let cacheContainer = activeAccount.map { cacheManager.cacheContainer(accountId: $0.id) } - let priceItemMap = coinPriceService.itemMap(coinUids: elements.compactMap { $0.priceCoinUid }) + let priceItemMap = coinPriceService.itemMap(coinUids: elements.compactMap(\.priceCoinUid)) let items: [Item] = elements.map { element in let item = Item( - element: element, - isMainNet: elementService.isMainNet(element: element) ?? fallbackIsMainNet, - balanceData: elementService.balanceData(element: element) ?? _cachedBalanceData(element: element, cacheContainer: cacheContainer) ?? fallbackBalanceData, - state: elementService.state(element: element) ?? fallbackAdapterState + element: element, + isMainNet: elementService.isMainNet(element: element) ?? fallbackIsMainNet, + balanceData: elementService.balanceData(element: element) ?? _cachedBalanceData(element: element, cacheContainer: cacheContainer) ?? fallbackBalanceData, + state: elementService.state(element: element) ?? fallbackAdapterState ) if let priceCoinUid = element.priceCoinUid { @@ -172,18 +171,18 @@ class WalletService { _syncTotalItem() coinPriceService.set( - coinUids: Set(elements.compactMap { $0.priceCoinUid }), - feeCoinUids: Set(elements.compactMap { $0.wallet }.compactMap { feeCoinProvider.feeToken(token: $0.token) }.map { $0.coin.uid }), - conversionCoinUids: Set(balanceConversionManager.conversionTokens.map { $0.coin.uid }) + coinUids: Set(elements.compactMap(\.priceCoinUid)), + feeCoinUids: Set(elements.compactMap(\.wallet).compactMap { feeCoinProvider.feeToken(token: $0.token) }.map(\.coin.uid)), + conversionCoinUids: Set(balanceConversionManager.conversionTokens.map(\.coin.uid)) ) - case .failed(let reason): + case let .failed(reason): internalState = .failed(reason: reason) } } private func _cachedBalanceData(element: WalletModule.Element, cacheContainer: EnabledWalletCacheManager.CacheContainer?) -> BalanceData? { switch element { - case .wallet(let wallet): return cacheContainer?.balanceData(wallet: wallet) + case let .wallet(wallet): return cacheContainer?.balanceData(wallet: wallet) default: return nil } } @@ -206,7 +205,7 @@ class WalletService { private func handleUpdateSortType() { queue.async { - guard case .loaded(let items) = self.internalState else { + guard case let .loaded(items) = self.internalState else { return } @@ -231,7 +230,7 @@ class WalletService { } private func _syncTotalItem() { - guard case .loaded(let items) = state else { + guard case let .loaded(items) = state else { return } @@ -263,10 +262,10 @@ class WalletService { } totalItem = TotalItem( - currencyValue: CurrencyValue(currency: coinPriceService.currency, value: total), - expired: expired, - convertedValue: convertedValue, - convertedValueExpired: expired || convertedValueExpired + currencyValue: CurrencyValue(currency: coinPriceService.currency, value: total), + expired: expired, + convertedValue: convertedValue, + convertedValueExpired: expired || convertedValueExpired ) } @@ -281,11 +280,9 @@ class WalletService { private var fallbackAdapterState: AdapterState { .syncing(progress: nil, lastBlockDate: nil) } - } extension WalletService: IWalletElementServiceDelegate { - func didUpdate(elementState: WalletModule.ElementState, elementService: IWalletElementService) { queue.async { self._sync(elementState: elementState, elementService: elementService) @@ -294,7 +291,7 @@ extension WalletService: IWalletElementServiceDelegate { func didUpdateElements(elementService: IWalletElementService) { queue.async { - guard case .loaded(let items) = self.internalState else { + guard case let .loaded(items) = self.internalState else { return } @@ -323,7 +320,7 @@ extension WalletService: IWalletElementServiceDelegate { func didUpdate(isMainNet: Bool, element: WalletModule.Element) { queue.async { - guard case .loaded(let items) = self.internalState, let item = self._item(element: element, items: items) else { + guard case let .loaded(items) = self.internalState, let item = self._item(element: element, items: items) else { return } @@ -335,13 +332,13 @@ extension WalletService: IWalletElementServiceDelegate { func didUpdate(balanceData: BalanceData, element: WalletModule.Element) { queue.async { - guard case .loaded(let items) = self.internalState, let item = self._item(element: element, items: items) else { + guard case let .loaded(items) = self.internalState, let item = self._item(element: element, items: items) else { return } item.balanceData = balanceData - if self.sortType == .balance, items.allSatisfy({ $0.state.isSynced }) { + if self.sortType == .balance, items.allSatisfy(\.state.isSynced) { self.internalState = .loaded(items: self._sorted(items: items)) } else { self.itemUpdatedRelay.accept(item) @@ -357,14 +354,14 @@ extension WalletService: IWalletElementServiceDelegate { func didUpdate(state: AdapterState, element: WalletModule.Element) { queue.async { - guard case .loaded(let items) = self.internalState, let item = self._item(element: element, items: items) else { + guard case let .loaded(items) = self.internalState, let item = self._item(element: element, items: items) else { return } let oldState = item.state item.state = state - if self.sortType == .balance, items.allSatisfy({ $0.state.isSynced }) { + if self.sortType == .balance, items.allSatisfy(\.state.isSynced) { self.internalState = .loaded(items: self._sorted(items: items)) } else { self.itemUpdatedRelay.accept(item) @@ -375,11 +372,9 @@ extension WalletService: IWalletElementServiceDelegate { } } } - } extension WalletService: IWalletCoinPriceServiceDelegate { - private func _handleUpdated(priceItemMap: [String: WalletCoinPriceService.Item], items: [Item]) { for item in items { if let priceCoinUid = item.element.priceCoinUid { @@ -393,29 +388,27 @@ extension WalletService: IWalletCoinPriceServiceDelegate { func didUpdateBaseCurrency() { queue.async { - guard case .loaded(let items) = self.internalState else { + guard case let .loaded(items) = self.internalState else { return } - let coinUids = Array(Set(items.compactMap { $0.element.priceCoinUid })) + let coinUids = Array(Set(items.compactMap(\.element.priceCoinUid))) self._handleUpdated(priceItemMap: self.coinPriceService.itemMap(coinUids: coinUids), items: items) } } func didUpdate(itemsMap: [String: WalletCoinPriceService.Item]) { queue.async { - guard case .loaded(let items) = self.internalState else { + guard case let .loaded(items) = self.internalState else { return } self._handleUpdated(priceItemMap: itemsMap, items: items) } } - } extension WalletService { - var activeAccountObservable: Observable { activeAccountRelay.asObservable() } @@ -424,7 +417,7 @@ extension WalletService { itemUpdatedRelay.asObservable() } - var accountsLostObservable: Observable<()> { + var accountsLostObservable: Observable { accountsLostRelay.asObservable() } @@ -474,7 +467,7 @@ extension WalletService { func item(element: WalletModule.Element) -> Item? { queue.sync { - guard case .loaded(let items) = internalState else { + guard case let .loaded(items) = internalState else { return nil } @@ -522,11 +515,9 @@ extension WalletService { accountRestoreWarningManager.setIgnoreWarning(account: account) activeAccountRelay.accept(account) } - } extension WalletService { - enum State: CustomStringConvertible { case noAccount case loading @@ -537,7 +528,7 @@ extension WalletService { switch self { case .noAccount: return "noAccount" case .loading: return "loading" - case .loaded(let items): return "loaded: \(items.count) items" + case let .loaded(items): return "loaded: \(items.count) items" case .failed: return "failed" } } @@ -564,5 +555,4 @@ extension WalletService { let convertedValue: CoinValue? let convertedValueExpired: Bool } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletSorter.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletSorter.swift index d03be88f48..cb2f7a4094 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletSorter.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletSorter.swift @@ -1,7 +1,6 @@ import Foundation class WalletSorter { - private let descending: (ISortableWalletItem, ISortableWalletItem) -> Bool = { lhsItem, rhsItem in let lhsBalance = lhsItem.balance let rhsBalance = rhsItem.balance @@ -22,7 +21,7 @@ class WalletSorter { switch sortType { case .balance: let nonZeroItems = items.filter { !$0.balance.isZero } - let zeroItems = items.filter { $0.balance.isZero } + let zeroItems = items.filter(\.balance.isZero) return nonZeroItems.sorted(by: descending) + zeroItems.sorted(by: descending) case .name: @@ -39,7 +38,6 @@ class WalletSorter { } } } - } protocol ISortableWalletItem { @@ -50,7 +48,6 @@ protocol ISortableWalletItem { } extension WalletService.Item: ISortableWalletItem { - var balance: Decimal { balanceData.available } @@ -62,11 +59,9 @@ extension WalletService.Item: ISortableWalletItem { var diff: Decimal? { priceItem?.diff } - } extension WalletTokenListService.Item: ISortableWalletItem { - var balance: Decimal { balanceData.available } @@ -78,5 +73,4 @@ extension WalletTokenListService.Item: ISortableWalletItem { var diff: Decimal? { priceItem?.diff } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewController.swift index 7c405a8954..152ba376d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewController.swift @@ -600,7 +600,7 @@ extension WalletViewController: UITableViewDelegate { bind(headerCell: cell) } - if let cell = cell as? TitledHighlightedDescriptionCell, let warningViewItem = warningViewItem { + if let cell = cell as? TitledHighlightedDescriptionCell, let warningViewItem { cell.set(backgroundStyle: .transparent, isFirst: true) cell.topOffset = .margin12 cell.bind(caution: warningViewItem) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewItemFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewItemFactory.swift index e18db43ccf..b2a320e804 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewItemFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewItemFactory.swift @@ -1,6 +1,6 @@ +import EvmKit import Foundation import MarketKit -import EvmKit class WalletViewItemFactory { private let minimumProgress = 10 @@ -11,17 +11,17 @@ class WalletViewItemFactory { let sendEnabled = state.spendAllowed(beforeSync: item.balanceData.sendBeforeSync) return BalanceTopViewItem( - isMainNet: item.isMainNet, - iconUrlString: iconUrlString(coin: item.element.coin, state: state), - placeholderIconName: item.element.wallet?.token.placeholderImageName ?? "placeholder_circle_32", - name: item.element.name, - blockchainBadge: item.element.wallet?.badge, - syncSpinnerProgress: syncSpinnerProgress(state: state), - indefiniteSearchCircle: indefiniteSearchCircle(state: state), - failedImageViewVisible: failedImageViewVisible(state: state), - sendEnabled: sendEnabled, - primaryValue: balanceHidden ? nil : primaryValue(item: item, balancePrimaryValue: balancePrimaryValue), - secondaryInfo: secondaryInfo(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) + isMainNet: item.isMainNet, + iconUrlString: iconUrlString(coin: item.element.coin, state: state), + placeholderIconName: item.element.wallet?.token.placeholderImageName ?? "placeholder_circle_32", + name: item.element.name, + blockchainBadge: item.element.wallet?.badge, + syncSpinnerProgress: syncSpinnerProgress(state: state), + indefiniteSearchCircle: indefiniteSearchCircle(state: state), + failedImageViewVisible: failedImageViewVisible(state: state), + sendEnabled: sendEnabled, + primaryValue: balanceHidden ? nil : primaryValue(item: item, balancePrimaryValue: balancePrimaryValue), + secondaryInfo: secondaryInfo(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) ) } @@ -32,15 +32,15 @@ class WalletViewItemFactory { return .customSyncing(main: main, secondary: secondary) } else if case .stopped = item.state { return .amount(viewItem: BalanceSecondaryAmountViewItem( - descriptionValue: (text: "balance.stopped".localized, dimmed: false), - secondaryValue: nil, - diff: nil + descriptionValue: (text: "balance.stopped".localized, dimmed: false), + secondaryValue: nil, + diff: nil )) } else { return .amount(viewItem: BalanceSecondaryAmountViewItem( - descriptionValue: rateValue(rateItem: item.priceItem), - secondaryValue: balanceHidden ? nil : secondaryValue(item: item, balancePrimaryValue: balancePrimaryValue), - diff: diff(rateItem: item.priceItem) + descriptionValue: rateValue(rateItem: item.priceItem), + secondaryValue: balanceHidden ? nil : secondaryValue(item: item, balancePrimaryValue: balancePrimaryValue), + diff: diff(rateItem: item.priceItem) )) } } @@ -55,7 +55,7 @@ class WalletViewItemFactory { private func syncSpinnerProgress(state: AdapterState) -> Int? { switch state { case let .syncing(progress, _): - if let progress = progress { + if let progress { return max(minimumProgress, progress) } else { return infiniteProgress @@ -68,7 +68,7 @@ class WalletViewItemFactory { private func indefiniteSearchCircle(state: AdapterState) -> Bool { switch state { - case .customSyncing(_, _, let progress): return progress == nil + case let .customSyncing(_, _, progress): return progress == nil default: return false } } @@ -81,7 +81,7 @@ class WalletViewItemFactory { } private func rateValue(rateItem: WalletCoinPriceService.Item?) -> (text: String?, dimmed: Bool) { - guard let rateItem = rateItem else { + guard let rateItem else { return (text: "n/a".localized, dimmed: true) } @@ -115,15 +115,15 @@ class WalletViewItemFactory { } } - private func coinValue(value: Decimal, decimalCount: Int, symbol: String? = nil, state: AdapterState, expanded: Bool = false) -> (text: String?, dimmed: Bool) { + private func coinValue(value: Decimal, decimalCount: Int, symbol: String? = nil, state: AdapterState, expanded _: Bool = false) -> (text: String?, dimmed: Bool) { ( - text: ValueFormatter.instance.formatShort(value: value, decimalCount: decimalCount, symbol: symbol), - dimmed: state != .synced + text: ValueFormatter.instance.formatShort(value: value, decimalCount: decimalCount, symbol: symbol), + dimmed: state != .synced ) } private func currencyValue(value: Decimal, state: AdapterState, priceItem: WalletCoinPriceService.Item?, expanded: Bool = false) -> (text: String?, dimmed: Bool) { - guard let priceItem = priceItem else { + guard let priceItem else { return (text: "---", dimmed: true) } @@ -131,40 +131,38 @@ class WalletViewItemFactory { let currencyValue = CurrencyValue(currency: price.currency, value: value * price.value) return ( - text: expanded ? ValueFormatter.instance.formatFull(currencyValue: currencyValue) : ValueFormatter.instance.formatShort(currencyValue: currencyValue), - dimmed: state != .synced || priceItem.expired + text: expanded ? ValueFormatter.instance.formatFull(currencyValue: currencyValue) : ValueFormatter.instance.formatShort(currencyValue: currencyValue), + dimmed: state != .synced || priceItem.expired ) } private func headerButtons(account: Account?) -> [WalletModule.Button: ButtonState] { - guard let account = account else { + guard let account else { return [:] } switch account.type { - case .cex(let cexAccount): + case let .cex(cexAccount): let withdrawalEnabled = cexAccount.cex.withdrawalAllowed ? ButtonState.enabled : .disabled return [ .deposit: .enabled, - .withdraw: withdrawalEnabled + .withdraw: withdrawalEnabled, ] case .evmPrivateKey, .hdExtendedKey, .mnemonic: return [ .send: .enabled, .receive: .enabled, - .swap: AppConfig.swapEnabled ? .enabled : .hidden + .swap: AppConfig.swapEnabled ? .enabled : .hidden, ] case .evmAddress, .tronAddress, .tonAddress: return [:] } } - } extension WalletViewItemFactory { - func viewItem(item: WalletService.Item, balancePrimaryValue: BalancePrimaryValue, balanceHidden: Bool) -> BalanceViewItem { BalanceViewItem( - element: item.element, - topViewItem: topViewItem(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) + element: item.element, + topViewItem: topViewItem(item: item, balancePrimaryValue: balancePrimaryValue, balanceHidden: balanceHidden) ) } @@ -181,12 +179,11 @@ extension WalletViewItemFactory { } return WalletModule.HeaderViewItem( - amount: amount, - amountExpired: balanceHidden ? false : totalItem.expired, - convertedValue: convertedValue, - convertedValueExpired: balanceHidden ? false : totalItem.convertedValueExpired, - buttons: headerButtons(account: account) + amount: amount, + amountExpired: balanceHidden ? false : totalItem.expired, + convertedValue: convertedValue, + convertedValueExpired: balanceHidden ? false : totalItem.convertedValueExpired, + buttons: headerButtons(account: account) ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewModel.swift index 5d6441a2a1..340b9e486f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletViewModel.swift @@ -292,9 +292,7 @@ extension WalletViewModel { do { self?.qrScanningRelay.accept(true) try await eventHandler.handle(event: scanned.trimmingCharacters(in: .whitespacesAndNewlines), eventType: [.walletConnectUri, .address]) - } catch { - - } + } catch {} } } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewController.swift index 34ec225a02..4777afe76a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewController.swift @@ -262,4 +262,4 @@ extension WalletConnectListViewController: SectionsDataSource { extension BottomSheetTitleView.Image { static let walletConnect: Self = .local(name: "wallet_connect_24", tint: .warning) -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewModel.swift index c2d33c099f..621ac9b7fb 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/List/WalletConnectListViewModel.swift @@ -38,7 +38,7 @@ class WalletConnectListViewModel { private func sync(items: [WalletConnectListService.Item]) { let viewItems = items.map { - let description = $0.blockchains.map { $0.shortName }.joined(separator: ", ") + let description = $0.blockchains.map(\.shortName).joined(separator: ", ") var badge: String? if $0.requestCount != 0 { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/PendingRequest/WalletConnectMainPendingRequestService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/PendingRequest/WalletConnectMainPendingRequestService.swift index f78f280237..4742fc6e25 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/PendingRequest/WalletConnectMainPendingRequestService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/PendingRequest/WalletConnectMainPendingRequestService.swift @@ -43,7 +43,7 @@ class WalletConnectMainPendingRequestService { } private func syncPendingRequests() { - guard let session = session else { + guard let session else { items = [] return } @@ -73,7 +73,7 @@ extension WalletConnectMainPendingRequestService { } func blockchain(chainId: String?) -> String? { - guard let chainId = chainId, + guard let chainId, let id = Int(chainId), let blockchain = evmBlockchainManager.blockchain(chainId: id) else { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/Eip155ProposalHandler.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/Eip155ProposalHandler.swift index a3a032f059..1dc6e270d2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/Eip155ProposalHandler.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/Eip155ProposalHandler.swift @@ -24,7 +24,8 @@ class Eip155ProposalHandler { for blockchain in namespace.chains ?? [] { guard let chainId = Int(blockchain.reference), - let evmBlockchain = evmBlockchainManager.blockchain(chainId: chainId) else { + let evmBlockchain = evmBlockchainManager.blockchain(chainId: chainId) + else { // can't get blockchain by chainId, or can't parse chainId continue } @@ -72,4 +73,4 @@ extension Eip155ProposalHandler: IProposalHandler { return set } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/ProposalChain.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/ProposalChain.swift index c4ebfd40c4..d171158542 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/ProposalChain.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/Proposal/ProposalChain.swift @@ -20,8 +20,8 @@ extension Session: INamespaceProvider { namespaces.reduce(into: [:]) { $0[$1.key] = ProposalNamespace( chains: Set($1.value.accounts.compactMap { account in - Blockchain(namespace: account.namespace, reference: account.reference) - }), + Blockchain(namespace: account.namespace, reference: account.reference) + }), methods: $1.value.methods, events: $1.value.events ) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainModule.swift index 4991c4a5aa..adca63d396 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainModule.swift @@ -1,12 +1,11 @@ -import UIKit -import ThemeKit +import MarketKit import RxSwift +import ThemeKit +import UIKit import WalletConnectSign import WalletConnectUtils -import MarketKit struct WalletConnectMainModule { - static func viewController(session: WalletConnectSign.Session? = nil, proposal: WalletConnectSign.Session.Proposal? = nil, sourceViewController: UIViewController?) -> UIViewController? { guard let account = App.shared.accountManager.activeAccount else { return nil @@ -19,14 +18,14 @@ struct WalletConnectMainModule { chain.append(handler: Eip155ProposalHandler(evmBlockchainManager: App.shared.evmBlockchainManager, account: account, supportedMethods: supportedMethods)) let mainService = WalletConnectMainService( - session: session, - proposal: proposal, - service: service, - manager: App.shared.walletConnectManager, - reachabilityManager: App.shared.reachabilityManager, - accountManager: App.shared.accountManager, - proposalHandler: chain, - proposalValidator: ProposalValidator() + session: session, + proposal: proposal, + service: service, + manager: App.shared.walletConnectManager, + reachabilityManager: App.shared.reachabilityManager, + accountManager: App.shared.accountManager, + proposalHandler: chain, + proposalValidator: ProposalValidator() ) return viewController(service: mainService, sourceViewController: sourceViewController) @@ -41,22 +40,21 @@ struct WalletConnectMainModule { ) let pendingRequestService = WalletConnectMainPendingRequestService( - service: service, - accountManager: App.shared.accountManager, - sessionManager: App.shared.walletConnectSessionManager, - requestHandler: App.shared.walletConnectRequestHandler, - evmBlockchainManager: App.shared.evmBlockchainManager, - signService: App.shared.walletConnectSessionManager.service) + service: service, + accountManager: App.shared.accountManager, + sessionManager: App.shared.walletConnectSessionManager, + requestHandler: App.shared.walletConnectRequestHandler, + evmBlockchainManager: App.shared.evmBlockchainManager, + signService: App.shared.walletConnectSessionManager.service + ) let pendingRequestViewModel = WalletConnectMainPendingRequestViewModel(service: pendingRequestService) viewController.pendingRequestViewModel = pendingRequestViewModel return ThemeNavigationController(rootViewController: viewController) } - } extension WalletConnectMainModule { - struct AppMetaItem { let name: String let url: String @@ -65,7 +63,7 @@ extension WalletConnectMainModule { } struct BlockchainSet { - static var empty: BlockchainSet = BlockchainSet(items: Set(), methods: Set(), events: Set()) + static var empty: BlockchainSet = .init(items: Set(), methods: Set(), events: Set()) var items: Set var methods: Set @@ -88,7 +86,7 @@ extension WalletConnectMainModule { hasher.combine(chainId) } - static func ==(lhs: BlockchainItem, rhs: BlockchainItem) -> Bool { + static func == (lhs: BlockchainItem, rhs: BlockchainItem) -> Bool { lhs.chainId == rhs.chainId } @@ -104,13 +102,13 @@ extension WalletConnectMainModule { case ready case killed(reason: KilledReason) - static func ==(lhs: State, rhs: State) -> Bool { + static func == (lhs: State, rhs: State) -> Bool { switch (lhs, rhs) { case (.idle, .idle): return true - case (.invalid(let lhsError), .invalid(let rhsError)): return "\(lhsError)" == "\(rhsError)" + case let (.invalid(lhsError), .invalid(rhsError)): return "\(lhsError)" == "\(rhsError)" case (.waitingForApproveSession, .waitingForApproveSession): return true case (.ready, .ready): return true - case (.killed(let reason), .killed(let reason2)): return reason == reason2 + case let (.killed(reason), .killed(reason2)): return reason == reason2 default: return false } } @@ -133,5 +131,4 @@ extension WalletConnectMainModule { case unsupportedChainId case noSuitableAccount } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainService.swift index 159584fce7..f61d0f2f47 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainService.swift @@ -1,9 +1,9 @@ -import RxSwift +import EvmKit +import HsToolKit import RxRelay -import WalletConnectUtils +import RxSwift import WalletConnectSign -import HsToolKit -import EvmKit +import WalletConnectUtils class WalletConnectMainService { private let disposeBag = DisposeBag() @@ -23,7 +23,7 @@ class WalletConnectMainService { } private let connectionStateRelay = PublishRelay() - private let requestRelay = PublishRelay() + private let requestRelay = PublishRelay() private let errorRelay = PublishRelay() private let sessionUpdatedRelay = PublishRelay() @@ -110,37 +110,35 @@ class WalletConnectMainService { } } - private func didDelete(topic: String, reason: WalletConnectSign.Reason) { + private func didDelete(topic: String, reason _: WalletConnectSign.Reason) { guard let currentTopic = session?.topic, currentTopic == topic else { return } - state = .killed(reason: .killSession) // todo: ??? + state = .killed(reason: .killSession) // TODO: ??? } - } extension WalletConnectMainService { - var activeAccountName: String? { accountManager.activeAccount?.name } var appMetaItem: WalletConnectMainModule.AppMetaItem? { - if let session = session { + if let session { return WalletConnectMainModule.AppMetaItem( - name: session.peer.name, - url: session.peer.url, - description: session.peer.description, - icons: session.peer.icons + name: session.peer.name, + url: session.peer.url, + description: session.peer.description, + icons: session.peer.icons ) } - if let proposal = proposal { + if let proposal { return WalletConnectMainModule.AppMetaItem( - name: proposal.proposer.name, - url: proposal.proposer.url, - description: proposal.proposer.description, - icons: proposal.proposer.icons + name: proposal.proposer.name, + url: proposal.proposer.url, + description: proposal.proposer.description, + icons: proposal.proposer.icons ) } @@ -164,7 +162,7 @@ extension WalletConnectMainService { } switch state { - case .invalid(let error): + case let .invalid(error): return error.smartDescription case .waitingForApproveSession: return "wallet_connect.connect_description".localized @@ -189,7 +187,7 @@ extension WalletConnectMainService { connectionStateRelay.asObservable() } - var proposalTimeOutAttentionObservable: Observable<()> { + var proposalTimeOutAttentionObservable: Observable { Observable.empty() } @@ -213,7 +211,7 @@ extension WalletConnectMainService { } func approveSession() { - guard let proposal = proposal else { + guard let proposal else { return } @@ -227,17 +225,18 @@ extension WalletConnectMainService { return } - //todo: check + // TODO: check let accounts: [WalletConnectUtils.Account] = blockchains.items.compactMap { item in Blockchain( namespace: item.namespace, - reference: item.chainId.description) - .flatMap { chain in - WalletConnectUtils.Account( - blockchain: chain, - address: item.address - ) - } + reference: item.chainId.description + ) + .flatMap { chain in + WalletConnectUtils.Account( + blockchain: chain, + address: item.address + ) + } } Task { [weak self, service, blockchains] in @@ -255,7 +254,7 @@ extension WalletConnectMainService { return } - if let proposal = proposal { + if let proposal { Task { [weak self, service] in defer { self?.state = .killed(reason: .rejectProposal) @@ -275,18 +274,16 @@ extension WalletConnectMainService { return } - guard let session = session else { + guard let session else { return } service.disconnect(topic: session.topic, reason: RejectionReason(code: 1, message: "Session Killed by User")) - state = .killed(reason: .killSession) //todo: ??? + state = .killed(reason: .killSession) // TODO: ??? } - } extension WalletConnectMainService { - struct RejectionReason: Reason { let code: Int let message: String @@ -296,5 +293,4 @@ extension WalletConnectMainService { let proposal: WalletConnectSign.Session.Proposal let appMeta: WalletConnectMainModule.AppMetaItem } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainViewController.swift index 155cbfa66e..ec6f290cce 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Main/WalletConnectMainViewController.swift @@ -304,7 +304,7 @@ extension WalletConnectMainViewController: SectionsDataSource { var sections = [SectionProtocol]() var rows = [RowProtocol]() - if let viewItem = viewItem { + if let viewItem { if let dAppMeta = viewItem.dAppMeta { sections.append(Section(id: "dapp-meta", rows: [headerRow(imageUrl: dAppMeta.icon, title: dAppMeta.name)])) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingModule.swift index 4997250696..826bda36f4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingModule.swift @@ -1,13 +1,11 @@ -import UIKit import ThemeKit +import UIKit struct WalletConnectPairingModule { - static func viewController() -> UIViewController { let service = WalletConnectPairingService(sessionManager: App.shared.walletConnectSessionManager) let viewModel = WalletConnectPairingViewModel(service: service) return WalletConnectPairingViewController(viewModel: viewModel) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingService.swift index 0e8fb716e9..e5fd5f3829 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingService.swift @@ -1,5 +1,5 @@ -import RxSwift import RxRelay +import RxSwift import WalletConnectPairing class WalletConnectPairingService { @@ -27,18 +27,15 @@ class WalletConnectPairingService { items = sessionManager.pairings.map { (pairing: WalletConnectPairing.Pairing) in let appName = pairing.peer?.name ?? "Unnamed" return Item(topic: pairing.topic, - appName: appName, - appUrl: pairing.peer?.url, - appDescription: pairing.peer?.description, - appIcons: pairing.peer?.icons ?? [] - ) + appName: appName, + appUrl: pairing.peer?.url, + appDescription: pairing.peer?.description, + appIcons: pairing.peer?.icons ?? []) } } - } extension WalletConnectPairingService { - var itemsObservable: Observable<[Item]> { itemsRelay.asObservable() } @@ -56,7 +53,7 @@ extension WalletConnectPairingService { .subscribe(onSuccess: { [weak self] _ in self?.pairingKillingRelay.accept(.completed) self?.syncPairings() - }, onError: { [weak self] error in + }, onError: { [weak self] _ in self?.pairingKillingRelay.accept(.failed) self?.syncPairings() }) @@ -64,26 +61,24 @@ extension WalletConnectPairingService { } func disconnectAll() { - let singles: [Single] = sessionManager.pairings.map { pairing in + let singles: [Single] = sessionManager.pairings.map { pairing in sessionManager - .disconnectPairing(topic: pairing.topic) - .map { _ in true } - .catchErrorJustReturn(false) + .disconnectPairing(topic: pairing.topic) + .map { _ in true } + .catchErrorJustReturn(false) } Single.zip(singles) - .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) - .subscribe(onSuccess: { [weak self] results in - self?.pairingKillingRelay.accept(results.first(where: { $0 == false }) == nil ? .completed : .failed) - self?.syncPairings() - }) - .disposed(by: disposeBag) + .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility)) + .subscribe(onSuccess: { [weak self] results in + self?.pairingKillingRelay.accept(results.first(where: { $0 == false }) == nil ? .completed : .failed) + self?.syncPairings() + }) + .disposed(by: disposeBag) } - } extension WalletConnectPairingService { - enum PairingKillingState { case processing case completed @@ -98,5 +93,4 @@ extension WalletConnectPairingService { let appDescription: String? let appIcons: [String] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewController.swift index bc78a4a523..c5509523fa 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewController.swift @@ -1,8 +1,8 @@ -import UIKit +import ComponentKit +import RxSwift import SectionsTableView import ThemeKit -import RxSwift -import ComponentKit +import UIKit class WalletConnectPairingViewController: ThemeViewController { private let viewModel: WalletConnectPairingViewModel @@ -21,7 +21,8 @@ class WalletConnectPairingViewController: ThemeViewController { hidesBottomBarWhenPushed = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -74,7 +75,7 @@ class WalletConnectPairingViewController: ThemeViewController { tableView.reload() } - private func cell(tableView: UITableView, viewItem: WalletConnectPairingViewModel.ViewItem, isFirst: Bool, isLast: Bool, action: (() -> ())? = nil) -> RowProtocol { + private func cell(tableView: UITableView, viewItem: WalletConnectPairingViewModel.ViewItem, isFirst: Bool, isLast: Bool, action: (() -> Void)? = nil) -> RowProtocol { let elements: [CellBuilderNew.CellElement] = [ .image32 { component in component.imageView.layer.cornerCurve = .continuous @@ -93,62 +94,61 @@ class WalletConnectPairingViewController: ThemeViewController { component.font = .subhead2 component.textColor = .themeGray component.text = viewItem.description ?? "---" - } + }, ]), .secondaryCircleButton { [weak self] component in component.button.set( - image: UIImage(named: "trash_20"), - style: .red + image: UIImage(named: "trash_20"), + style: .red ) component.onTap = { self?.onTapDisconnect(topic: viewItem.topic) } - } + }, ] return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: tableView, - id: viewItem.title, - height: .heightDoubleLineCell, - autoDeselect: true, - bind: { cell in cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) }, - action: action + rootElement: .hStack(elements), + tableView: tableView, + id: viewItem.title, + height: .heightDoubleLineCell, + autoDeselect: true, + bind: { cell in cell.set(backgroundStyle: .lawrence, isFirst: isFirst, isLast: isLast) }, + action: action ) } private func section(viewItems: [WalletConnectPairingViewModel.ViewItem]) -> SectionProtocol { Section( - id: "section-list", - headerState: .margin(height: .margin12), - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - cell(tableView: tableView, - viewItem: viewItem, - isFirst: index == 0, - isLast: index == viewItems.count - 1 - ) - } + id: "section-list", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + cell(tableView: tableView, + viewItem: viewItem, + isFirst: index == 0, + isLast: index == viewItems.count - 1) + } ) } private func disconnectAllSection() -> SectionProtocol { Section( - id: "button_section", - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "delete_all", - image: .local(UIImage(named: "trash_24")?.withTintColor(.themeLucian)), - title: .body("wallet_connect.paired_dapps.disconnect_all".localized, color: .themeLucian), - autoDeselect: true, - isFirst: true, - isLast: true, - action: { [weak self] in - self?.onTapDisconnectAll() - } - ) - ] + id: "button_section", + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( + id: "delete_all", + image: .local(UIImage(named: "trash_24")?.withTintColor(.themeLucian)), + title: .body("wallet_connect.paired_dapps.disconnect_all".localized, color: .themeLucian), + autoDeselect: true, + isFirst: true, + isLast: true, + action: { [weak self] in + self?.onTapDisconnectAll() + } + ), + ] ) } @@ -159,11 +159,9 @@ class WalletConnectPairingViewController: ThemeViewController { private func onTapDisconnectAll() { viewModel.onDisconnectAll() } - } extension WalletConnectPairingViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections = [section(viewItems: viewItems)] if viewItems.count > 1 { @@ -171,5 +169,4 @@ extension WalletConnectPairingViewController: SectionsDataSource { } return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewModel.swift index 74c5ab1687..04790eff8d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Pairings/WalletConnectPairingViewModel.swift @@ -1,13 +1,13 @@ -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class WalletConnectPairingViewModel { private let service: WalletConnectPairingService private let disposeBag = DisposeBag() private let viewItemRelay = BehaviorRelay<[ViewItem]>(value: []) - private let showDisconnectingRelay = PublishRelay<()>() + private let showDisconnectingRelay = PublishRelay() private let showDisconnectedRelay = PublishRelay() init(service: WalletConnectPairingService) { @@ -34,16 +34,14 @@ class WalletConnectPairingViewModel { case .failed: showDisconnectedRelay.accept(false) } } - } extension WalletConnectPairingViewModel { - var viewItemsDriver: Driver<[ViewItem]> { viewItemRelay.asDriver() } - var showDisconnectingSignal: Signal<()> { + var showDisconnectingSignal: Signal { showDisconnectingRelay.asSignal() } @@ -51,7 +49,6 @@ extension WalletConnectPairingViewModel { showDisconnectedRelay.asSignal() } - func onDisconnect(topic: String) { service.disconnect(topic: topic) } @@ -59,16 +56,13 @@ extension WalletConnectPairingViewModel { func onDisconnectAll() { service.disconnectAll() } - } extension WalletConnectPairingViewModel { - struct ViewItem { let topic: String let title: String let description: String? let imageUrl: String? } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestService.swift index 136212d34c..a62d6f1483 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestService.swift @@ -1,5 +1,5 @@ -import Foundation import EvmKit +import Foundation class WCSendEthereumTransactionRequestService { private let request: WalletConnectRequest @@ -14,22 +14,21 @@ class WCSendEthereumTransactionRequestService { self.request = request signService = baseService } - } extension WCSendEthereumTransactionRequestService { - var transactionData: TransactionData { TransactionData( - to: payload.transaction.to, - value: payload.transaction.value, - input: payload.transaction.data + to: payload.transaction.to, + value: payload.transaction.value, + input: payload.transaction.data ) } var gasPrice: GasPrice? { if let maxFeePerGas = payload.transaction.maxFeePerGas, - let maxPriorityFeePerGas = payload.transaction.maxPriorityFeePerGas { + let maxPriorityFeePerGas = payload.transaction.maxPriorityFeePerGas + { return GasPrice.eip1559(maxFeePerGas: maxFeePerGas, maxPriorityFeePerGas: maxPriorityFeePerGas) } @@ -43,5 +42,4 @@ extension WCSendEthereumTransactionRequestService { func reject() { signService.rejectRequest(id: request.id) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewController.swift index b59c20efdf..7ff08d7e3a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewController.swift @@ -1,9 +1,9 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import RxSwift import RxCocoa -import ComponentKit +import RxSwift +import ThemeKit +import UIKit class WCSendEthereumTransactionRequestViewController: SendEvmTransactionViewController { private let viewModel: WCSendEthereumTransactionRequestViewModel @@ -17,7 +17,8 @@ class WCSendEthereumTransactionRequestViewController: SendEvmTransactionViewCont super.init(transactionViewModel: transactionViewModel, settingsViewModel: settingsViewModel) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -51,6 +52,7 @@ class WCSendEthereumTransactionRequestViewController: SendEvmTransactionViewCont dismiss(animated: true) } + override func handleSending() { HudHelper.instance.show(banner: .approving) } @@ -61,5 +63,4 @@ class WCSendEthereumTransactionRequestViewController: SendEvmTransactionViewCont super.handleSendSuccess(transactionHash: transactionHash) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewModel.swift index 5be37ef31b..dc33b6497b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/SendEthereumTransaction/WCSendEthereumTransactionRequestViewModel.swift @@ -6,11 +6,9 @@ class WCSendEthereumTransactionRequestViewModel { init(service: WCSendEthereumTransactionRequestService) { self.service = service } - } extension WCSendEthereumTransactionRequestViewModel { - func approve(transactionHash: Data) { service.approve(transactionHash: transactionHash) } @@ -18,5 +16,4 @@ extension WCSendEthereumTransactionRequestViewModel { func reject() { service.reject() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestService.swift index 2bf6104522..0be9da9f96 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestService.swift @@ -48,26 +48,25 @@ class WCSignMessageRequestService { private func sign(message: Data, isLegacy: Bool = false) throws -> Data { try signer.signed(message: message, isLegacy: isLegacy) } - } extension WCSignMessageRequestService { var sections: [Section] { var sections = [Section]() - if let domain = domain { + if let domain { sections.append(Section(header: nil, items: [.domain(domain)])) } var infoItems: [Item] = [ - .dApp(name: request.payload.dAppName) + .dApp(name: request.payload.dAppName), ] if let name = request.chain.chainName, let address = request.chain.address { infoItems.append(.blockchain(name: name, address: address)) } sections.append(Section(header: nil, items: infoItems)) - if let message = message { + if let message { sections.append(Section(header: .signMessage, items: [.message(message)])) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestViewController.swift index c13e189f32..09ec6c225a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Confirmations/Sign/WCSignMessageRequestViewController.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SectionsTableView import ComponentKit import RxSwift +import SectionsTableView +import ThemeKit +import UIKit class WCSignMessageRequestViewController: ThemeViewController { private let viewModel: WCSignMessageRequestViewModel @@ -21,7 +21,8 @@ class WCSignMessageRequestViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -81,11 +82,9 @@ class WCSignMessageRequestViewController: ThemeViewController { private func dismiss() { dismiss(animated: true) } - } extension WCSignMessageRequestViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { viewModel.sections.enumerated().map { index, section in Section( @@ -97,11 +96,11 @@ extension WCSignMessageRequestViewController: SectionsDataSource { switch item { case let .value(title: title, value: value): return tableView.universalRow48( - id: "value_\(index)_\(itemIndex)", - title: .subhead2(title), - value: .subhead1(value), - isFirst: itemIndex == 0, - isLast: itemIndex == section.items.count - 1 + id: "value_\(index)_\(itemIndex)", + title: .subhead2(title), + value: .subhead1(value), + isFirst: itemIndex == 0, + isLast: itemIndex == section.items.count - 1 ) case let .message(text): return tableView.messageRow(text: text) @@ -110,5 +109,4 @@ extension WCSignMessageRequestViewController: SectionsDataSource { ) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Eip155RequestFactory.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Eip155RequestFactory.swift index 2517de9aa0..f5e40e744c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Eip155RequestFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Eip155RequestFactory.swift @@ -18,14 +18,15 @@ extension Eip155RequestFactory { } guard let chainId = Int(request.chainId.reference), - let blockchain = evmBlockchainManager.blockchain(chainId: chainId) else { + let blockchain = evmBlockchainManager.blockchain(chainId: chainId) + else { throw WalletConnectRequest.CreationError.invalidChain } guard let address = try? WalletConnectManager.evmAddress( - account: account, - chain: evmBlockchainManager.chain(blockchainType: blockchain.type) - ) + account: account, + chain: evmBlockchainManager.chain(blockchainType: blockchain.type) + ) else { throw WalletConnectRequest.CreationError.cantCreateAddress } @@ -33,9 +34,9 @@ extension Eip155RequestFactory { let chain = WalletConnectRequest.Chain(id: chainId, chainName: blockchain.name, address: address.eip55) return WalletConnectRequest( - id: request.id.intValue, - chain: chain, - payload: payload + id: request.id.intValue, + chain: chain, + payload: payload ) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WCEthereumTransactionPayload.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WCEthereumTransactionPayload.swift index d97553fc3c..08d308ad4d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WCEthereumTransactionPayload.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WCEthereumTransactionPayload.swift @@ -15,9 +15,10 @@ class WCEthereumTransactionPayload: WCRequestPayload { super.init(dAppName: dAppName, data: data) } - required public convenience init(dAppName: String, from anyCodable: AnyCodable) throws { + public required convenience init(dAppName: String, from anyCodable: AnyCodable) throws { guard let transactions = try? anyCodable.get([WCEthereumTransaction].self), - let wcTransaction = transactions.first else { + let wcTransaction = transactions.first + else { throw WCRequestPayload.ParsingError.badJSONRPCRequest } @@ -25,7 +26,7 @@ class WCEthereumTransactionPayload: WCRequestPayload { self.init(dAppName: dAppName, transaction: transaction, data: anyCodable.encoded) } - class func module(request: WalletConnectRequest) -> UIViewController? { + class func module(request _: WalletConnectRequest) -> UIViewController? { nil } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WalletConnectTransaction.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WalletConnectTransaction.swift index 0dd4cac342..202a1ee8c6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WalletConnectTransaction.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/EthereumTransaction/WalletConnectTransaction.swift @@ -1,6 +1,6 @@ -import Foundation -import EvmKit import BigInt +import EvmKit +import Foundation struct WCEthereumTransaction: Codable { public let from: String diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Sign/WCSignMessagePayload.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Sign/WCSignMessagePayload.swift index 161780709c..12a5058424 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Sign/WCSignMessagePayload.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Sign/WCSignMessagePayload.swift @@ -11,11 +11,11 @@ class WCSignMessagePayload: WCRequestPayload { super.init(dAppName: dAppName, data: data) } - required public convenience init(dAppName: String, from anyCodable: AnyCodable) throws { - self.init(dAppName: dAppName, data: try Self.data(from: anyCodable)) + public required convenience init(dAppName: String, from anyCodable: AnyCodable) throws { + try self.init(dAppName: dAppName, data: Self.data(from: anyCodable)) } - class func data(from anyCodable: AnyCodable) throws -> Data { + class func data(from _: AnyCodable) throws -> Data { throw ParsingError.badJSONRPCRequest } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WCWalletPayload.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WCWalletPayload.swift index 23624cb0b6..5f925410fc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WCWalletPayload.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WCWalletPayload.swift @@ -13,10 +13,11 @@ class WCWalletPayload: WCRequestPayload { super.init(dAppName: dAppName, data: data) } - required public convenience init(dAppName: String, from anyCodable: AnyCodable) throws { + public required convenience init(dAppName: String, from anyCodable: AnyCodable) throws { let chain = try anyCodable.get([WalletConnectChain].self) guard let chain = chain.first, - let chainId = Int(chain.chainId.replacingOccurrences(of: "0x", with: ""), radix: 16) else { + let chainId = Int(chain.chainId.replacingOccurrences(of: "0x", with: ""), radix: 16) + else { throw ParsingError.badJSONRPCRequest } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WalletConnectChain.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WalletConnectChain.swift index 28c6833fba..f9abfe7ff1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WalletConnectChain.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/Wallet/WalletConnectChain.swift @@ -13,4 +13,4 @@ struct WalletConnectNativeCurrency: Codable { let name: String let symbol: String let decimals: Int -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/WalletConnectRequestChain.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/WalletConnectRequestChain.swift index 2098db1287..2994a01d9b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/WalletConnectRequestChain.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Request/Handlers/WalletConnectRequestChain.swift @@ -1,6 +1,6 @@ import Foundation -import WalletConnectSign import UIKit +import WalletConnectSign protocol IWalletConnectRequestHandler { func handle(session: Session, request: Request) -> WalletConnectRequestChain.RequestResult @@ -79,7 +79,7 @@ extension WalletConnectRequestChain { var error: Error? { switch self { - case .unsuccessful(let error): return error + case let .unsuccessful(error): return error case .handled, .request: return nil } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/ScanQr/WalletConnectScanQrViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/ScanQr/WalletConnectScanQrViewModel.swift index 64e2acc8a7..8c88d81a98 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/ScanQr/WalletConnectScanQrViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/ScanQr/WalletConnectScanQrViewModel.swift @@ -1,18 +1,12 @@ -import RxSwift import RxCocoa +import RxSwift class WalletConnectScanQrViewModel { private let openErrorRelay = PublishRelay() - init() { - } - + init() {} } extension WalletConnectScanQrViewModel { - - func didScan(string: String) { - - } - -} \ No newline at end of file + func didScan(string _: String) {} +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Views/SendEthereumErrorCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Views/SendEthereumErrorCell.swift index 101fd03637..ee5f07e028 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Views/SendEthereumErrorCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/Views/SendEthereumErrorCell.swift @@ -25,7 +25,8 @@ class SendEthereumErrorCell: UITableViewCell { errorLabel.textColor = .themeLucian } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -40,13 +41,10 @@ class SendEthereumErrorCell: UITableViewCell { return isVisible ? Self.height(text: text, containerWidth: width) : 0 } - } extension SendEthereumErrorCell { - static func height(text: String, containerWidth: CGFloat) -> CGFloat { text.height(forContainerWidth: containerWidth - SendEthereumErrorCell.padding * 2, font: SendEthereumErrorCell.font) + SendEthereumErrorCell.padding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectManager.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectManager.swift index 949ca014b7..31de1c8012 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectManager.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectManager.swift @@ -33,5 +33,4 @@ class WalletConnectManager { return try? evmBlockchainManager.evmKitManager(blockchainType: blockchainType).evmKitWrapper(account: account, blockchainType: blockchainType) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift index 524477c36b..a4dee9ece7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift @@ -1,18 +1,18 @@ -import Foundation +import Combine import CryptoSwift -import RxSwift +import Foundation +import HsToolKit import RxRelay -import Combine +import RxSwift import Starscream import WalletConnectKMS -import WalletConnectSign -import WalletConnectRelay -import WalletConnectUtils import WalletConnectNetworking import WalletConnectPairing -import HsToolKit +import WalletConnectRelay +import WalletConnectSign +import WalletConnectUtils -extension Starscream.WebSocket: WebSocketConnecting { } +extension Starscream.WebSocket: WebSocketConnecting {} struct SocketFactory: WebSocketFactory { func create(with url: URL) -> WebSocketConnecting { @@ -28,9 +28,9 @@ class WalletConnectService { private let receiveSessionRelay = PublishRelay() private let deleteSessionRelay = PublishRelay<(String, WalletConnectSign.Reason)>() - private let sessionsItemUpdatedRelay = PublishRelay<()>() - private let pendingRequestsUpdatedRelay = PublishRelay<()>() - private let pairingUpdatedRelay = PublishRelay<()>() + private let sessionsItemUpdatedRelay = PublishRelay() + private let pendingRequestsUpdatedRelay = PublishRelay() + private let pairingUpdatedRelay = PublishRelay() private let sessionRequestReceivedRelay = PublishRelay() private let socketConnectionStatusRelay = PublishRelay() @@ -46,10 +46,10 @@ class WalletConnectService { self.connectionService = connectionService self.logger = logger let metadata = WalletConnectSign.AppMetadata( - name: info.name, - description: info.description, - url: info.url, - icons: info.icons + name: info.name, + description: info.description, + url: info.url, + icons: info.icons ) Networking.configure(projectId: info.projectId, socketFactory: SocketFactory(), socketConnectionType: .manual) @@ -64,43 +64,42 @@ class WalletConnectService { func setUpAuthSubscribing() { Sign.instance.socketConnectionStatusPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] status in - self?.didChangeSocketConnectionStatus(status) - }.store(in: &publishers) + .receive(on: DispatchQueue.main) + .sink { [weak self] status in + self?.didChangeSocketConnectionStatus(status) + }.store(in: &publishers) Sign.instance.sessionProposalPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] sessionProposal in - self?.didReceive(sessionProposal: sessionProposal.proposal) - }.store(in: &publishers) + .receive(on: DispatchQueue.main) + .sink { [weak self] sessionProposal in + self?.didReceive(sessionProposal: sessionProposal.proposal) + }.store(in: &publishers) Sign.instance.sessionSettlePublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] session in - self?.didSettle(session: session) - }.store(in: &publishers) + .receive(on: DispatchQueue.main) + .sink { [weak self] session in + self?.didSettle(session: session) + }.store(in: &publishers) Sign.instance.sessionUpdatePublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] pair in - self?.didUpdate(sessionTopic: pair.sessionTopic, namespaces: pair.namespaces) - }.store(in: &publishers) + .receive(on: DispatchQueue.main) + .sink { [weak self] pair in + self?.didUpdate(sessionTopic: pair.sessionTopic, namespaces: pair.namespaces) + }.store(in: &publishers) Sign.instance.sessionRequestPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] sessionRequest in - self?.didReceive(sessionRequest: sessionRequest.request) - }.store(in: &publishers) + .receive(on: DispatchQueue.main) + .sink { [weak self] sessionRequest in + self?.didReceive(sessionRequest: sessionRequest.request) + }.store(in: &publishers) Sign.instance.sessionDeletePublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] tuple in - self?.didDelete(sessionTopic: tuple.0, reason: tuple.1) - }.store(in: &publishers) + .receive(on: DispatchQueue.main) + .sink { [weak self] tuple in + self?.didDelete(sessionTopic: tuple.0, reason: tuple.1) + }.store(in: &publishers) } - private func updateSessions() { sessionsItemUpdatedRelay.accept(()) } @@ -108,11 +107,9 @@ class WalletConnectService { private func updatePairings() { pairingUpdatedRelay.accept(()) } - } extension WalletConnectService { - public func didReceive(sessionProposal: Session.Proposal) { logger?.debug("WC v2 SignClient did receive session proposal: \(sessionProposal.id) : proposer: \(sessionProposal.proposer.name)") receiveProposalSubject.onNext(sessionProposal) @@ -129,7 +126,7 @@ extension WalletConnectService { logger?.debug("WC v2 SignClient did receive session response: \(sessionResponse.topic) : chainId: \(sessionResponse.chainId ?? "")") } - public func didReceive(event: Session.Event, sessionTopic: String, chainId: WalletConnectSign.Blockchain?) { + public func didReceive(event: Session.Event, sessionTopic: String, chainId _: WalletConnectSign.Blockchain?) { logger?.debug("WC v2 SignClient did receive session event: \(event.name) : session: \(sessionTopic)") } @@ -139,7 +136,7 @@ extension WalletConnectService { updateSessions() } - public func didUpdate(sessionTopic: String, namespaces: [String: SessionNamespace]) { + public func didUpdate(sessionTopic: String, namespaces _: [String: SessionNamespace]) { logger?.debug("WC v2 SignClient did update session: \(sessionTopic)") } @@ -153,13 +150,11 @@ extension WalletConnectService { logger?.debug("WC v2 SignClient change socketStatus: \(status)") socketConnectionStatus = status.connectionState } - } extension WalletConnectService { - // helpers - public func ping(topic: String, completion: @escaping (Result) -> ()) { + public func ping(topic: String, completion: @escaping (Result) -> Void) { Task(priority: .userInitiated) { @MainActor in do { try await Sign.instance.ping(topic: topic) @@ -175,7 +170,7 @@ extension WalletConnectService { Sign.instance.getSessions() } - public var sessionsUpdatedObservable: Observable<()> { + public var sessionsUpdatedObservable: Observable { sessionsItemUpdatedRelay.asObservable() } @@ -184,7 +179,7 @@ extension WalletConnectService { Sign.instance.getPendingRequests() } - public var pendingRequestsUpdatedObservable: Observable<()> { + public var pendingRequestsUpdatedObservable: Observable { pendingRequestsUpdatedRelay.asObservable() } @@ -193,11 +188,11 @@ extension WalletConnectService { Pair.instance.getPairings() } - public var pairingUpdatedObservable: Observable<()> { + public var pairingUpdatedObservable: Observable { pairingUpdatedRelay.asObservable() } - public func disconnectPairing(topic: String) -> Single<()> { + public func disconnectPairing(topic: String) -> Single { Single.create { observer in Task { [weak self] in do { @@ -244,7 +239,7 @@ extension WalletConnectService { try await Pair.instance.pair(uri: uri) self?.updatePairings() } catch { - //can't pair with dApp, duplicate pairing or can't parse uri + // can't pair with dApp, duplicate pairing or can't parse uri throw error } } @@ -255,9 +250,9 @@ extension WalletConnectService { Task { [logger] in do { let eip155 = WalletConnectSign.SessionNamespace( - accounts: accounts, - methods: methods, - events: events + accounts: accounts, + methods: methods, + events: events ) try await Sign.instance.approve(proposalId: proposal.id, namespaces: ["eip155": eip155]) } catch { @@ -277,7 +272,7 @@ extension WalletConnectService { } } - public func disconnect(topic: String, reason: WalletConnectSign.Reason) { + public func disconnect(topic: String, reason _: WalletConnectSign.Reason) { Task { [weak self, logger] in do { try await Sign.instance.disconnect(topic: topic) @@ -288,13 +283,13 @@ extension WalletConnectService { } } - //Works with Requests + // Works with Requests public var sessionRequestReceivedObservable: Observable { sessionRequestReceivedRelay.asObservable() } public func sign(request: WalletConnectSign.Request, result: Data) { - let result = AnyCodable(result.hs.hexString)// Signer.signEth(request: request) + let result = AnyCodable(result.hs.hexString) // Signer.signEth(request: request) Task { [weak self] in do { try await Sign.instance.respond(topic: request.topic, requestId: request.id, response: .response(result)) @@ -323,23 +318,20 @@ struct WalletConnectClientInfo { } extension WalletConnectSign.Session: Hashable { - public var id: Int { hashValue } - public static func ==(lhs: WalletConnectSign.Session, rhs: WalletConnectSign.Session) -> Bool { + public static func == (lhs: WalletConnectSign.Session, rhs: WalletConnectSign.Session) -> Bool { lhs.topic == rhs.topic } public func hash(into hasher: inout Hasher) { hasher.combine(topic) } - } extension WalletConnectService: IWalletConnectSignService { - func approveRequest(id: Int, result: Data) { guard let request = pendingRequests.first(where: { $0.id.intValue == id }) else { return @@ -353,19 +345,16 @@ extension WalletConnectService: IWalletConnectSignService { } reject(request: request) } - } extension RPCID { - var intValue: Int { - (left?.hashValue ?? 0) + Int(right ?? 0) //todo: id potentially can be wrong + (left?.hashValue ?? 0) + Int(right ?? 0) // TODO: id potentially can be wrong } var int64Value: Int64 { Int64(intValue) } - } extension WalletConnectSign.SocketConnectionStatus { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift index e8054718d8..2e4dcd473f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift @@ -1,13 +1,12 @@ +import Combine import Foundation import HsToolKit -import WalletConnectSign -import WalletConnectUtils -import WalletConnectRelay -import Combine -import RxSwift import RxCocoa import RxRelay - +import RxSwift +import WalletConnectRelay +import WalletConnectSign +import WalletConnectUtils class WalletConnectSocketConnectionService { private static let retryInterval = 10 @@ -70,22 +69,20 @@ class WalletConnectSocketConnectionService { cancellables.forEach { cancellable in cancellable.cancel() } cancellables.removeAll() - guard let relayClient = relayClient else { + guard let relayClient else { return } relayClient.socketConnectionStatusPublisher - .sink { [weak self] status in - self?.sync(status: status) - } - .store(in: &cancellables) + .sink { [weak self] status in + self?.sync(status: status) + } + .store(in: &cancellables) retry() } - } extension WalletConnectSocketConnectionService { - func retry() { do { try relayClient?.connect() @@ -113,11 +110,9 @@ extension WalletConnectSocketConnectionService { var statusObservable: Observable { statusRelay.asObservable() } - } extension WalletConnectSocketConnectionService { - enum Status { case disconnected case connecting @@ -129,8 +124,5 @@ extension WalletConnectSocketConnectionService { case .disconnected: return self == .disconnected } } - } - } - diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseBlockchainService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseBlockchainService.swift index 10f2cd20d4..9511b3e7ed 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseBlockchainService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseBlockchainService.swift @@ -13,7 +13,8 @@ class ChooseBlockchainService { init(accountType: AccountType, accountName: String, accountFactory: AccountFactory, accountManager: AccountManager, walletManager: WalletManager, - evmBlockchainManager: EvmBlockchainManager, marketKit: MarketKit.Kit) { + evmBlockchainManager: EvmBlockchainManager, marketKit: MarketKit.Kit) + { self.accountType = accountType self.accountName = accountName self.accountFactory = accountFactory @@ -44,17 +45,14 @@ class ChooseBlockchainService { } walletManager.save(wallets: wallets) - } catch { } + } catch {} } - } extension ChooseBlockchainService: IChooseWatchService { - func watch(enabledUids: [String]) { let account = accountFactory.watchAccount(type: accountType, name: accountName) accountManager.save(account: account) enableWallets(account: account, enabledBlockchainUids: enabledUids) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseCoinService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseCoinService.swift index c5f8d7510d..68397e3902 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseCoinService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseCoinService.swift @@ -22,20 +22,20 @@ class ChooseCoinService { } private func btcItems() -> [WatchModule.Item] { - guard case .hdExtendedKey(let key) = accountType, case .public = key else { + guard case let .hdExtendedKey(key) = accountType, case .public = key else { return [] } let blockchainTypes: [BlockchainType] = [.bitcoin, .bitcoinCash, .ecash, .litecoin, .dash] - let tokenQueries = blockchainTypes.map { $0.nativeTokenQueries }.flatMap { $0 } + let tokenQueries = blockchainTypes.map(\.nativeTokenQueries).flatMap { $0 } guard let tokens = try? marketKit.tokens(queries: tokenQueries) else { return [] } return tokens - .filter { accountType.supports(token: $0) } - .map { .coin(token: $0) } + .filter { accountType.supports(token: $0) } + .map { .coin(token: $0) } } private func enableWallets(account: Account, enabledTokensUids: [String]) { @@ -51,15 +51,12 @@ class ChooseCoinService { walletManager.save(wallets: wallets) } - } extension ChooseCoinService: IChooseWatchService { - func watch(enabledUids: [String]) { let account = accountFactory.watchAccount(type: accountType, name: accountName) accountManager.save(account: account) enableWallets(account: account, enabledTokensUids: enabledUids) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewController.swift index 3b92b2d93e..bcebb37282 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewController.swift @@ -1,11 +1,11 @@ +import ComponentKit import Foundation -import UIKit -import ThemeKit -import SectionsTableView -import RxSwift import RxCocoa -import ComponentKit +import RxSwift +import SectionsTableView +import ThemeKit import UIExtensions +import UIKit class ChooseWatchViewController: CoinToggleViewController { private let viewModel: ChooseWatchViewModel @@ -21,7 +21,8 @@ class ChooseWatchViewController: CoinToggleViewController { super.init(viewModel: viewModel) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -65,5 +66,4 @@ class ChooseWatchViewController: CoinToggleViewController { @objc private func onTapWatch() { viewModel.onTapWatch() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewModel.swift index e53506f1d1..bcd0424533 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/ChooseWatch/ChooseWatchViewModel.swift @@ -1,8 +1,8 @@ import Foundation import MarketKit -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift protocol IChooseWatchService { var items: [WatchModule.Item] { get } @@ -49,11 +49,9 @@ class ChooseWatchViewModel { } } } - } extension ChooseWatchViewModel { - var title: String { switch watchType { case .evmAddress: return "watch_address.choose_blockchain".localized @@ -74,11 +72,9 @@ extension ChooseWatchViewModel { service.watch(enabledUids: enabledBlockchainUids) watchRelay.accept(()) } - } extension ChooseWatchViewModel: ICoinToggleViewModel { - var viewItemsDriver: Driver<[CoinToggleViewModel.ViewItem]> { Driver.just(viewItems) } @@ -101,8 +97,7 @@ extension ChooseWatchViewModel: ICoinToggleViewModel { } } - func onTapSettings(uid: String) { } - func onTapInfo(uid: String) { } - func onUpdate(filter: String) {} - + func onTapSettings(uid _: String) {} + func onTapInfo(uid _: String) {} + func onUpdate(filter _: String) {} } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressService.swift index 93956ed497..61fd65b2d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressService.swift @@ -1,7 +1,7 @@ +import EvmKit import Foundation -import RxSwift import RxRelay -import EvmKit +import RxSwift class WatchEvmAddressService { private let disposeBag = DisposeBag() @@ -19,9 +19,9 @@ class WatchEvmAddressService { private func sync(addressState: AddressService.State) { switch addressState { - case .success(let address): + case let .success(address): do { - state = .ready(address: try EvmKit.Address(hex: address.raw), domain: address.domain) + state = try .ready(address: EvmKit.Address(hex: address.raw), domain: address.domain) } catch { state = .notReady } @@ -29,11 +29,9 @@ class WatchEvmAddressService { state = .notReady } } - } extension WatchEvmAddressService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -44,11 +42,9 @@ extension WatchEvmAddressService { case .notReady: return nil } } - } extension WatchEvmAddressService { - enum State { case ready(address: EvmKit.Address, domain: String?) case notReady @@ -62,11 +58,9 @@ extension WatchEvmAddressService { var domain: String? { switch self { - case .ready(_, let domain): return domain + case let .ready(_, domain): return domain case .notReady: return nil } } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressViewModel.swift index e5cf200353..d28a41cb1d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchEvmAddressViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class WatchEvmAddressViewModel { private let service: WatchEvmAddressService @@ -9,25 +9,22 @@ class WatchEvmAddressViewModel { init(service: WatchEvmAddressService) { self.service = service } - } extension WatchEvmAddressViewModel: IWatchSubViewModel { - var watchEnabled: Bool { service.state.watchEnabled } var watchEnabledObservable: Observable { - service.stateObservable.map { $0.watchEnabled } + service.stateObservable.map(\.watchEnabled) } var domainObservable: Observable { - service.stateObservable.map { $0.domain } + service.stateObservable.map(\.domain) } func resolve() -> AccountType? { service.resolve() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchModule.swift index dff8f52704..e069e13a1a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchModule.swift @@ -13,7 +13,8 @@ struct WatchModule { .append(handler: udnAddressParserItem) if let httpSyncSource = App.shared.evmSyncSourceManager.httpSyncSource(blockchainType: .ethereum), - let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) { + let ensAddressParserItem = EnsAddressParserItem(rpcSource: httpSyncSource.rpcSource, rawAddressParserItem: evmAddressParserItem) + { addressParserChain.append(handler: ensAddressParserItem) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyService.swift index 0f249e14b9..1222de0475 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyService.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import HdWalletKit +import RxRelay +import RxSwift class WatchPublicKeyService { private let disposeBag = DisposeBag() @@ -12,11 +12,9 @@ class WatchPublicKeyService { stateRelay.accept(state) } } - } extension WatchPublicKeyService { - func set(text: String) { if text.trimmingCharacters(in: .whitespaces).isEmpty { state = .notReady @@ -24,11 +22,9 @@ extension WatchPublicKeyService { state = .ready(text: text) } } - } extension WatchPublicKeyService { - var stateObservable: Observable { stateRelay.asObservable() } @@ -53,11 +49,9 @@ extension WatchPublicKeyService { throw ResolveError.notReady } } - } extension WatchPublicKeyService { - enum State { case ready(text: String) case notReady @@ -75,5 +69,4 @@ extension WatchPublicKeyService { case notSupportedDerivedType case nonPublicKey } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyViewModel.swift index 75c86fc86b..8a156bce20 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchPublicKeyViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class WatchPublicKeyViewModel { private let service: WatchPublicKeyService @@ -11,11 +11,9 @@ class WatchPublicKeyViewModel { init(service: WatchPublicKeyService) { self.service = service } - } extension WatchPublicKeyViewModel { - var cautionDriver: Driver { cautionRelay.asDriver() } @@ -24,17 +22,15 @@ extension WatchPublicKeyViewModel { service.set(text: text) cautionRelay.accept(nil) } - } extension WatchPublicKeyViewModel: IWatchSubViewModel { - var watchEnabled: Bool { service.state.watchEnabled } var watchEnabledObservable: Observable { - service.stateObservable.map { $0.watchEnabled } + service.stateObservable.map(\.watchEnabled) } var domainObservable: Observable { @@ -52,5 +48,4 @@ extension WatchPublicKeyViewModel: IWatchSubViewModel { return nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchService.swift index 5280fa74ad..4ba2573df3 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchService.swift @@ -8,11 +8,9 @@ class WatchService { init(accountFactory: AccountFactory) { self.accountFactory = accountFactory } - } extension WatchService { - var defaultAccountName: String { accountFactory.nextWatchAccountName } @@ -29,5 +27,4 @@ extension WatchService { self.name = name } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressService.swift index 1e5687485a..f7d27c8ef2 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressService.swift @@ -1,6 +1,6 @@ import Foundation -import RxSwift import RxRelay +import RxSwift import TronKit class WatchTronAddressService { @@ -19,54 +19,48 @@ class WatchTronAddressService { private func sync(addressState: AddressService.State) { switch addressState { - case .success(let address): - do { - state = .ready(address: try TronKit.Address(address: address.raw), domain: address.domain) - } catch { - state = .notReady - } - default: + case let .success(address): + do { + state = try .ready(address: TronKit.Address(address: address.raw), domain: address.domain) + } catch { state = .notReady + } + default: + state = .notReady } } - } extension WatchTronAddressService { - var stateObservable: Observable { stateRelay.asObservable() } func resolve() -> AccountType? { switch state { - case let .ready(address, _): return AccountType.tronAddress(address: address) - case .notReady: return nil + case let .ready(address, _): return AccountType.tronAddress(address: address) + case .notReady: return nil } } - } extension WatchTronAddressService { - enum State { case ready(address: TronKit.Address, domain: String?) case notReady var watchEnabled: Bool { switch self { - case .ready: return true - case .notReady: return false + case .ready: return true + case .notReady: return false } } var domain: String? { switch self { - case .ready(_, let domain): return domain - case .notReady: return nil + case let .ready(_, domain): return domain + case .notReady: return nil } } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressViewModel.swift index c8ba9d754f..43433f5255 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronAddressViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift class WatchTronAddressViewModel { private let service: WatchTronAddressService @@ -9,25 +9,22 @@ class WatchTronAddressViewModel { init(service: WatchTronAddressService) { self.service = service } - } extension WatchTronAddressViewModel: IWatchSubViewModel { - var watchEnabled: Bool { service.state.watchEnabled } var watchEnabledObservable: Observable { - service.stateObservable.map { $0.watchEnabled } + service.stateObservable.map(\.watchEnabled) } var domainObservable: Observable { - service.stateObservable.map { $0.domain } + service.stateObservable.map(\.domain) } func resolve() -> AccountType? { service.resolve() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronService.swift index 5e50b15663..c04c500f0d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchTronService.swift @@ -1,5 +1,5 @@ -import TronKit import MarketKit +import TronKit class WatchTronService { private let accountFactory: AccountFactory @@ -13,11 +13,9 @@ class WatchTronService { self.walletManager = walletManager self.marketKit = marketKit } - } extension WatchTronService { - func enableWatch(accountType: AccountType, accountName: String) { let account = accountFactory.watchAccount(type: accountType, name: accountName) accountManager.save(account: account) @@ -30,5 +28,4 @@ extension WatchTronService { walletManager.save(wallets: [Wallet(token: token, account: account)]) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewController.swift index 6f276d51f1..eac4991f0e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewController.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit -import SnapKit -import SectionsTableView import ComponentKit -import RxSwift import RxCocoa +import RxSwift +import SectionsTableView +import SnapKit +import ThemeKit import UIExtensions +import UIKit class WatchViewController: KeyboardAwareViewController { private let viewModel: WatchViewModel @@ -44,7 +44,8 @@ class WatchViewController: KeyboardAwareViewController { super.init(scrollViews: [tableView], accessoryView: gradientWrapperView) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -109,7 +110,7 @@ class WatchViewController: KeyboardAwareViewController { self?.navigationItem.rightBarButtonItem?.isEnabled = enabled self?.nextButton.isEnabled = enabled } - subscribe(disposeBag, viewModel.proceedSignal) { [weak self] (watchType, accountType, name) in + subscribe(disposeBag, viewModel.proceedSignal) { [weak self] watchType, accountType, name in self?.proceedToNextPage(watchType: watchType, accountType: accountType, name: name) } @@ -133,14 +134,14 @@ class WatchViewController: KeyboardAwareViewController { private func onTapWatchType() { let alertController = AlertRouter.module( - title: "watch_address.watch_by".localized, - viewItems: WatchModule.WatchType.allCases.enumerated().map { index, watchType in - AlertViewItem( - text: watchType.title, - description: watchType.subtitle, - selected: self.watchType == watchType - ) - } + title: "watch_address.watch_by".localized, + viewItems: WatchModule.WatchType.allCases.enumerated().map { _, watchType in + AlertViewItem( + text: watchType.title, + description: watchType.subtitle, + selected: self.watchType == watchType + ) + } ) { [weak self] index in self?.viewModel.onSelect(watchType: WatchModule.WatchType.allCases[index]) } @@ -157,11 +158,9 @@ class WatchViewController: KeyboardAwareViewController { navigationController?.pushViewController(viewController, animated: true) } - } extension WatchViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { var sections: [SectionProtocol] = [ Section( @@ -177,98 +176,98 @@ extension WatchViewController: SectionsDataSource { cell: nameCell, id: "name", height: .heightSingleLineCell - ) + ), ] - ) + ), ] sections.append( - Section( - id: "watch-type", - footerState: .margin(height: .margin32), - rows: [ - tableView.universalRow48( - id: "watch_type", - title: .body("watch_address.by".localized), - value: .subhead1(watchType.title, color: .themeGray), - accessoryType: .dropdown, - autoDeselect: true, - isFirst: true, - isLast: true - ) { [weak self] in - self?.onTapWatchType() - } - ] - ) + Section( + id: "watch-type", + footerState: .margin(height: .margin32), + rows: [ + tableView.universalRow48( + id: "watch_type", + title: .body("watch_address.by".localized), + value: .subhead1(watchType.title, color: .themeGray), + accessoryType: .dropdown, + autoDeselect: true, + isFirst: true, + isLast: true + ) { [weak self] in + self?.onTapWatchType() + }, + ] + ) ) switch watchType { case .evmAddress: let evmAddressSection: SectionProtocol = Section( - id: "address", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: evmAddressCell, - id: "address-input", - dynamicHeight: { [weak self] width in - self?.evmAddressCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: evmAddressCautionCell, - id: "address-caution", - dynamicHeight: { [weak self] width in - self?.evmAddressCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "address", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: evmAddressCell, + id: "address-input", + dynamicHeight: { [weak self] width in + self?.evmAddressCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: evmAddressCautionCell, + id: "address-caution", + dynamicHeight: { [weak self] width in + self?.evmAddressCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ) sections.append(evmAddressSection) case .tronAddress: let tronAddressSection: SectionProtocol = Section( - id: "address", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: tronAddressCell, - id: "address-input", - dynamicHeight: { [weak self] width in - self?.tronAddressCell.height(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: tronAddressCautionCell, - id: "address-caution", - dynamicHeight: { [weak self] width in - self?.tronAddressCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "address", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: tronAddressCell, + id: "address-input", + dynamicHeight: { [weak self] width in + self?.tronAddressCell.height(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: tronAddressCautionCell, + id: "address-caution", + dynamicHeight: { [weak self] width in + self?.tronAddressCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ) sections.append(tronAddressSection) case .publicKey: let publicKeySection: SectionProtocol = Section( - id: "public-key-input", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: publicKeyInputCell, - id: "public-key-input", - dynamicHeight: { [weak self] width in - self?.publicKeyInputCell.cellHeight(containerWidth: width) ?? 0 - } - ), - StaticRow( - cell: publicKeyCautionCell, - id: "public-key-caution", - dynamicHeight: { [weak self] width in - self?.publicKeyCautionCell.height(containerWidth: width) ?? 0 - } - ) - ] + id: "public-key-input", + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: publicKeyInputCell, + id: "public-key-input", + dynamicHeight: { [weak self] width in + self?.publicKeyInputCell.cellHeight(containerWidth: width) ?? 0 + } + ), + StaticRow( + cell: publicKeyCautionCell, + id: "public-key-caution", + dynamicHeight: { [weak self] width in + self?.publicKeyCautionCell.height(containerWidth: width) ?? 0 + } + ), + ] ) sections.append(publicKeySection) @@ -276,5 +275,4 @@ extension WatchViewController: SectionsDataSource { return sections } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewModel.swift index 27cc6db1b8..a466f01d89 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Watch/WatchViewModel.swift @@ -1,7 +1,7 @@ import Foundation -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift protocol IWatchSubViewModel: AnyObject { var watchEnabled: Bool { get } @@ -53,16 +53,14 @@ class WatchViewModel { } private func sync(domain: String?) { - if let domain = domain, service.name == nil { + if let domain, service.name == nil { service.set(name: domain) nameRelay.accept(domain) } } - } extension WatchViewModel { - var watchTypeDriver: Driver { watchTypeRelay.asDriver() } @@ -110,5 +108,4 @@ extension WatchViewModel { proceedRelay.accept((watchType, accountType, service.resolvedName)) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeScreenViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeScreenViewController.swift index 61d1e01ca5..b6e991b4be 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeScreenViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeScreenViewController.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class WelcomeScreenViewController: ThemeViewController { private let scrollView = UIScrollView() @@ -16,7 +16,7 @@ class WelcomeScreenViewController: ThemeViewController { private let slides = [ Slide(title: "intro.unchain_assets.title".localized, description: "intro.unchain_assets.description".localized, image: "Intro - Unchain Assets"), Slide(title: "intro.go_borderless.title".localized, description: "intro.go_borderless.description".localized, image: "Intro - Go Borderless"), - Slide(title: "intro.stay_private.title".localized, description: "intro.stay_private.description".localized, image: "Intro - Stay Private") + Slide(title: "intro.stay_private.title".localized, description: "intro.stay_private.description".localized, image: "Intro - Stay Private"), ] override init() { @@ -25,7 +25,8 @@ class WelcomeScreenViewController: ThemeViewController { super.init() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -213,11 +214,9 @@ class WelcomeScreenViewController: ThemeViewController { UIApplication.shared.windows.first { $0.isKeyWindow }?.set(newRootController: MainModule.instance()) } } - } extension WelcomeScreenViewController: UIScrollViewDelegate { - func scrollViewDidScroll(_ scrollView: UIScrollView) { pageIndex = Int(round(scrollView.contentOffset.x / view.frame.width)) @@ -232,9 +231,9 @@ extension WelcomeScreenViewController: UIScrollViewDelegate { let pagePercent = CGFloat(1) / CGFloat(slides.count - 1) - for i in 0..= (fi - 1) * pagePercent && currentPercent <= (fi + 1) * pagePercent { + if currentPercent >= (fi - 1) * pagePercent, currentPercent <= (fi + 1) * pagePercent { let offset: CGFloat = abs((fi * pagePercent) - currentPercent) let percent: CGFloat = offset / pagePercent @@ -244,15 +243,12 @@ extension WelcomeScreenViewController: UIScrollViewDelegate { } } } - } extension WelcomeScreenViewController { - private struct Slide { let title: String let description: String let image: String } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeTextView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeTextView.swift index 520c468d91..d201831a4b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeTextView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Welcome/WelcomeTextView.swift @@ -1,9 +1,8 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class WelcomeTextView: UIView { - init(title: String, description: String) { super.init(frame: .zero) @@ -35,8 +34,8 @@ class WelcomeTextView: UIView { descriptionLabel.text = description } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetConfiguration.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetConfiguration.swift index 50dcc7d5f5..d3b3c124c0 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetConfiguration.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetConfiguration.swift @@ -7,10 +7,10 @@ public struct ActionSheetConfiguration { public var ignoreInteractiveFalseMoving: Bool = true - public var coverBackgroundColor: UIColor = UIColor(white: 0, alpha: 0.5) + public var coverBackgroundColor: UIColor = .init(white: 0, alpha: 0.5) public var presentAnimationDuration: TimeInterval = 0.3 - public var presentAnimationCurve: UIView.AnimationOptions = UIView.AnimationOptions(rawValue: 5 << 16) + public var presentAnimationCurve: UIView.AnimationOptions = .init(rawValue: 5 << 16) public var dismissAnimationDuration: TimeInterval = 0.2 public var dismissAnimationCurve: UIView.AnimationCurve = .easeIn @@ -27,5 +27,4 @@ public struct ActionSheetConfiguration { sideMargin = 0 } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetControllerNew.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetControllerNew.swift index 3a301e40df..2f846ce610 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetControllerNew.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetControllerNew.swift @@ -1,12 +1,12 @@ -import UIKit -import SnapKit -import RxSwift import RxCocoa +import RxSwift +import SnapKit import UIExtensions +import UIKit public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { private var disposeBag = DisposeBag() - public var onDeinit: (() -> ())? + public var onDeinit: (() -> Void)? private let content: UIViewController private weak var viewDelegate: ActionSheetViewDelegate? @@ -23,7 +23,8 @@ public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { private var savedConstraints: [NSLayoutConstraint]? - public required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError() } @@ -49,16 +50,16 @@ public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { modalPresentationStyle = .custom NotificationCenter.default.addObserver(self, - selector: #selector(keyboardNotification(notification:)), - name: UIResponder.keyboardWillChangeFrameNotification, - object: nil) + selector: #selector(keyboardNotification(notification:)), + name: UIResponder.keyboardWillChangeFrameNotification, + object: nil) } - public override var shouldAutomaticallyForwardAppearanceMethods: Bool { + override public var shouldAutomaticallyForwardAppearanceMethods: Bool { false } - public override func viewDidLoad() { + override public func viewDidLoad() { super.viewDidLoad() if configuration.tapToDismiss { @@ -78,8 +79,8 @@ public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { } // lifecycle - public override func viewWillAppear(_ animated: Bool) { - if let savedConstraints = savedConstraints { + override public func viewWillAppear(_ animated: Bool) { + if let savedConstraints { view.superview?.addConstraints(savedConstraints) } @@ -92,15 +93,15 @@ public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { disposeBag = DisposeBag() keyboardHeightRelay - .asObservable() - .observeOn(MainScheduler.instance) - .subscribe(onNext: { [weak self] height in - self?.setContentViewPosition(animated: true) - }) - .disposed(by: disposeBag) + .asObservable() + .observeOn(MainScheduler.instance) + .subscribe(onNext: { [weak self] _ in + self?.setContentViewPosition(animated: true) + }) + .disposed(by: disposeBag) } - public override func viewDidAppear(_ animated: Bool) { + override public func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if !ignoreByInteractivePresentingBreak { content.endAppearanceTransition() @@ -109,7 +110,7 @@ public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { didAppear = true } - public override func viewWillDisappear(_ animated: Bool) { + override public func viewWillDisappear(_ animated: Bool) { dismissing = true savedConstraints = view.superview?.constraints @@ -121,7 +122,7 @@ public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { super.viewWillDisappear(animated) } - public override func viewDidDisappear(_ animated: Bool) { + override public func viewDidDisappear(_ animated: Bool) { content.endAppearanceTransition() super.viewDidDisappear(animated) @@ -146,12 +147,10 @@ public class ActionSheetControllerNew: UIViewController, IDeinitDelegate { removeChildController() NotificationCenter.default.removeObserver(self) } - } // Child management extension ActionSheetControllerNew { - private func addChildController() { addChild(content) view.addSubview(content.view) @@ -172,10 +171,10 @@ extension ActionSheetControllerNew { content.view.snp.remakeConstraints { maker in maker.leading.trailing.equalToSuperview().inset(configuration.sideMargin) - if configuration.style == .sheet { // content controller from bottom of superview + if configuration.style == .sheet { // content controller from bottom of superview maker.top.equalToSuperview() maker.bottom.equalToSuperview().inset(configuration.sideMargin + keyboardHeightRelay.value).priority(.required) - } else { // content controller by center of superview + } else { // content controller by center of superview maker.centerX.equalToSuperview() maker.centerY.equalToSuperview().priority(.low) maker.bottom.lessThanOrEqualTo(view.snp.bottom).inset(keyboardHeightRelay.value + 16) @@ -185,8 +184,8 @@ extension ActionSheetControllerNew { } } if let superview = view.superview { - if animated && didAppear { - UIView.animate(withDuration: configuration.presentAnimationDuration) { () -> Void in + if animated, didAppear { + UIView.animate(withDuration: configuration.presentAnimationDuration) { () in superview.layoutIfNeeded() } } else { @@ -194,11 +193,9 @@ extension ActionSheetControllerNew { } } } - } extension ActionSheetControllerNew: ActionSheetView { - public func contentWillDismissed() { dismissing = true } @@ -212,11 +209,9 @@ extension ActionSheetControllerNew: ActionSheetView { public func didChangeHeight() { setContentViewPosition(animated: true) } - } extension ActionSheetControllerNew: InteractiveTransitionDelegate { - public func start(direction: TransitionDirection) { interactiveTransitionDelegate?.start(direction: direction) dismissing = direction == .dismiss @@ -246,11 +241,9 @@ extension ActionSheetControllerNew: InteractiveTransitionDelegate { public func fail(direction: TransitionDirection) { interactiveTransitionDelegate?.fail(direction: direction) } - } extension ActionSheetControllerNew { - override open var childForStatusBarStyle: UIViewController? { content } @@ -258,7 +251,6 @@ extension ActionSheetControllerNew { override open var childForStatusBarHidden: UIViewController? { content } - } @available(iOS 13.0, *) diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModifier.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModifier.swift index 00b62e530a..078039f16f 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModifier.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModifier.swift @@ -112,11 +112,11 @@ struct BooleanActionSheetModifier: ViewModifier { } public extension View { - func bottomSheet( + func bottomSheet( isPresented: Binding, onDismiss: (() -> Void)? = nil, - @ViewBuilder content: @escaping () -> Content - ) -> some View where Content: View { + @ViewBuilder content: @escaping () -> some View + ) -> some View { modifier( BooleanActionSheetModifier( isPresented: isPresented, @@ -126,11 +126,11 @@ public extension View { ) } - func bottomSheet( + func bottomSheet( item: Binding, onDismiss: (() -> Void)? = nil, - @ViewBuilder content: @escaping (Item) -> Content - ) -> some View where Item: Identifiable, Content: View { + @ViewBuilder content: @escaping (Item) -> some View + ) -> some View where Item: Identifiable { modifier( ActionSheetModifier( item: item, diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModule.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModule.swift index a4cd3cf0f0..7f16a9cd4e 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetModule.swift @@ -1,9 +1,9 @@ import UIKit public protocol ActionSheetView: AnyObject { - func contentWillDismissed() //child viewController will start dismissing programmatically - func dismissView(animated: Bool) // child viewController can't get access to parentVC from iOS 5.* - func didChangeHeight() // Change height flicker for .sheet + func contentWillDismissed() // child viewController will start dismissing programmatically + func dismissView(animated: Bool) // child viewController can't get access to parentVC from iOS 5.* + func didChangeHeight() // Change height flicker for .sheet } public protocol ActionSheetViewDelegate: AnyObject { @@ -13,16 +13,15 @@ public protocol ActionSheetViewDelegate: AnyObject { func didInteractiveDismissed() } -extension ActionSheetViewDelegate { - - public var actionSheetView: ActionSheetView? { +public extension ActionSheetViewDelegate { + var actionSheetView: ActionSheetView? { get { nil } - set { () } + set { () } } - public var height: CGFloat? { + var height: CGFloat? { nil } - public func didInteractiveDismissed() {} + func didInteractiveDismissed() {} } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetTapView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetTapView.swift index 99b9cc1a0c..6388c5913d 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetTapView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/ActionSheetTapView.swift @@ -1,21 +1,21 @@ import UIKit class ActionSheetTapView: UIView { - var handleTap: (() -> ())? + var handleTap: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(onTap)) - self.addGestureRecognizer(gestureRecognizer) + addGestureRecognizer(gestureRecognizer) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func onTap() { handleTap?() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetAnimator.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetAnimator.swift index a3042dc0e0..68dd1281e7 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetAnimator.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetAnimator.swift @@ -25,36 +25,35 @@ public class ActionSheetAnimator: NSObject, UIViewControllerTransitioningDelegat public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { driver?.add(to: presented) return ActionSheetPresentationController(driver: driver, presentedViewController: presented, - presenting: presenting ?? source, - configuration: configuration) + presenting: presenting ?? source, + configuration: configuration) } - + // Animation - public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + public func animationController(forPresented _: UIViewController, presenting _: UIViewController, source _: UIViewController) -> UIViewControllerAnimatedTransitioning? { switch configuration.style { case .sheet: return MovingPresentAnimation(duration: configuration.presentAnimationDuration, animationCurve: configuration.presentAnimationCurve) case .alert: return AlphaPresentAnimation(duration: configuration.presentAnimationDuration, animationCurve: configuration.presentAnimationCurve) } } - public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + public func animationController(forDismissed _: UIViewController) -> UIViewControllerAnimatedTransitioning? { switch configuration.style { case .sheet: return MovingDismissAnimation(duration: configuration.dismissAnimationDuration, animationCurve: configuration.dismissAnimationCurve) case .alert: return AlphaDismissAnimation(duration: configuration.dismissAnimationDuration, animationCurve: configuration.dismissAnimationCurve) } } - + // Interaction - public func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { + public func interactionControllerForPresentation(using _: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { driver } - public func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { + public func interactionControllerForDismissal(using _: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { driver } deinit { // print("deinit \(self)") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetPresentationController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetPresentationController.swift index 98a30eecda..2989697920 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetPresentationController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/ActionSheetPresentationController.swift @@ -1,6 +1,6 @@ -import UIKit -import UIExtensions import SnapKit +import UIExtensions +import UIKit class ActionSheetPresentationController: UIPresentationController { private let tapView = ActionSheetTapView() @@ -22,7 +22,7 @@ class ActionSheetPresentationController: UIPresentationController { override func presentationTransitionWillBegin() { super.presentationTransitionWillBegin() - guard let presentedView = presentedView else { + guard let presentedView else { return } containerView?.addSubview(tapView) @@ -60,7 +60,7 @@ class ActionSheetPresentationController: UIPresentationController { if completed { driver?.direction = .dismiss } else { - self.tapView.removeFromSuperview() + tapView.removeFromSuperview() } } @@ -72,25 +72,24 @@ class ActionSheetPresentationController: UIPresentationController { self?.tapView.alpha = 0 } } - + override func dismissalTransitionDidEnd(_ completed: Bool) { super.dismissalTransitionDidEnd(completed) if completed { delegate?.presentationControllerDidDismiss?(self) - self.tapView.removeFromSuperview() + tapView.removeFromSuperview() } } - + private func alongsideTransition(_ action: @escaping () -> Void) { - guard let coordinator = self.presentedViewController.transitionCoordinator else { + guard let coordinator = presentedViewController.transitionCoordinator else { action() return } - coordinator.animate(alongsideTransition: { (_) in + coordinator.animate(alongsideTransition: { _ in action() }, completion: nil) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaDismissAnimation.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaDismissAnimation.swift index 8449849437..0b9b51a184 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaDismissAnimation.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaDismissAnimation.swift @@ -13,10 +13,9 @@ class AlphaDismissAnimation: BaseAnimation { transitionContext.view(forKey: .from)?.alpha = 0 } - animator.addCompletion { (position) in + animator.addCompletion { _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) } return animator } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaPresentAnimation.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaPresentAnimation.swift index d3dd4e072d..20d1ecae5e 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaPresentAnimation.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/AlphaPresentAnimation.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class AlphaPresentAnimation: BaseAnimation { private let animationCurve: UIView.AnimationOptions @@ -11,13 +11,12 @@ class AlphaPresentAnimation: BaseAnimation { override func animator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { UIViewPropertyAnimator.runningPropertyAnimator(withDuration: duration, - delay: 0, - options: animationCurve, - animations: { - transitionContext.view(forKey: .to)?.alpha = 1 - }, completion: { position in - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) + delay: 0, + options: animationCurve, + animations: { + transitionContext.view(forKey: .to)?.alpha = 1 + }, completion: { _ in + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + }) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/BaseAnimation.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/BaseAnimation.swift index d574d039f3..ac3d40a64b 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/BaseAnimation.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/BaseAnimation.swift @@ -8,20 +8,17 @@ class BaseAnimation: NSObject { self.duration = duration } - func animator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { + func animator(using _: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { fatalError("Must be implemented by inheritors") } - } -extension BaseAnimation: UIViewControllerAnimatedTransitioning { - - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { +extension BaseAnimation: UIViewControllerAnimatedTransitioning { + func transitionDuration(using _: UIViewControllerContextTransitioning?) -> TimeInterval { duration } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { animator(using: transitionContext).startAnimation() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingDismissAnimation.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingDismissAnimation.swift index f5e5e1f9ab..15f45150c2 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingDismissAnimation.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingDismissAnimation.swift @@ -16,19 +16,16 @@ class MovingDismissAnimation: BaseAnimation { let animator = UIViewPropertyAnimator(duration: duration, curve: animationCurve) { from.frame = from.frame.offsetBy(dx: 0, dy: from.height) } - - animator.addCompletion { (position) in + + animator.addCompletion { _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) } return animator } - } extension MovingDismissAnimation { - func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { animator(using: transitionContext) } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingPresentAnimation.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingPresentAnimation.swift index 1e3070e600..a7be10fd49 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingPresentAnimation.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/Animations/MovingPresentAnimation.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class MovingPresentAnimation: BaseAnimation { private let animationCurve: UIView.AnimationOptions @@ -9,7 +9,7 @@ class MovingPresentAnimation: BaseAnimation { super.init(duration: duration) } - override func animator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { + override func animator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { let to = transitionContext.view(forKey: .to) to?.snp.remakeConstraints { maker in @@ -19,13 +19,12 @@ class MovingPresentAnimation: BaseAnimation { } return UIViewPropertyAnimator.runningPropertyAnimator(withDuration: duration, - delay: 0, - options: animationCurve, - animations: { - to?.superview?.layoutIfNeeded() - }, completion: { position in - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) - } - + delay: 0, + options: animationCurve, + animations: { + to?.superview?.layoutIfNeeded() + }, completion: { _ in + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + }) + } } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/DismissPanGestureRecognizer.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/DismissPanGestureRecognizer.swift index 06b9584900..d470101913 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/DismissPanGestureRecognizer.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/DismissPanGestureRecognizer.swift @@ -1,11 +1,9 @@ import UIKit class DismissPanGestureRecognizer: UIPanGestureRecognizer { - override func touchesBegan(_ touches: Set, with event: UIEvent) { - if (self.state == .began) { return } + if state == .began { return } super.touchesBegan(touches, with: event) - self.state = .began + state = .began } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/InteractiveTransitionDelegate.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/InteractiveTransitionDelegate.swift index 4821920e2d..a087379d34 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/InteractiveTransitionDelegate.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/InteractiveTransitionDelegate.swift @@ -11,9 +11,9 @@ public protocol InteractiveTransitionDelegate: AnyObject { } // Make pure swift option methods for delegate -extension InteractiveTransitionDelegate { - public func start(direction: TransitionDirection) {} - public func move(direction: TransitionDirection, percent: CGFloat) {} - public func end(direction: TransitionDirection, cancelled: Bool) {} - public func fail(direction: TransitionDirection) {} +public extension InteractiveTransitionDelegate { + func start(direction _: TransitionDirection) {} + func move(direction _: TransitionDirection, percent _: CGFloat) {} + func end(direction _: TransitionDirection, cancelled _: Bool) {} + func fail(direction _: TransitionDirection) {} } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/TransitionDriver.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/TransitionDriver.swift index d6b3ead2c2..57f1121be1 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/TransitionDriver.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/ActionSheetNew/Transition/TransitionDriver.swift @@ -10,8 +10,8 @@ class TransitionDriver: UIPercentDrivenInteractiveTransition { var speedMultiplier: CGFloat = 1 func add(to controller: UIViewController) { presentedController = controller - - panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handle(_ :))) + + panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handle(_:))) presentedController?.view.addGestureRecognizer(panRecognizer!) } @@ -25,8 +25,8 @@ class TransitionDriver: UIPercentDrivenInteractiveTransition { return gestureIsActive } } - - set { } + + set {} } var interactiveTransitionStarted: Bool { @@ -39,7 +39,6 @@ class TransitionDriver: UIPercentDrivenInteractiveTransition { } } - @objc private func handle(_ recognizer: UIPanGestureRecognizer) { switch direction { case .present: @@ -52,11 +51,9 @@ class TransitionDriver: UIPercentDrivenInteractiveTransition { deinit { // print("deinit \(self)") } - } -extension TransitionDriver { // Gesture Handling - +extension TransitionDriver { // Gesture Handling private func handlePresentation(recognizer: UIPanGestureRecognizer) { switch recognizer.state { case .began: @@ -76,7 +73,7 @@ extension TransitionDriver { // Gesture Handling finish() interactiveTransitionDelegate?.end(direction: .present, cancelled: false) } - + case .failed: cancel() interactiveTransitionDelegate?.fail(direction: .present) @@ -85,7 +82,7 @@ extension TransitionDriver { // Gesture Handling break } } - + private func handleDismiss(recognizer: UIPanGestureRecognizer) { switch recognizer.state { case .began: @@ -95,7 +92,7 @@ extension TransitionDriver { // Gesture Handling presentedController?.dismiss(animated: true) // Start the new one interactiveTransitionDelegate?.start(direction: .dismiss) } - + case .changed: let newValue = percentComplete + recognizer.incrementToBottom(maxTranslation: maxTranslation) update(newValue) @@ -119,20 +116,19 @@ extension TransitionDriver { // Gesture Handling break } } - + var maxTranslation: CGFloat { presentedController?.view.frame.height ?? 0 } - + private var isRunning: Bool { percentComplete != 0 } } private extension UIPanGestureRecognizer { - func projectedLocation(decelerationRate: UIScrollView.DecelerationRate) -> CGPoint { - guard let view = view else { + guard let view else { return .zero } var loc = location(in: view) @@ -146,18 +142,17 @@ private extension UIPanGestureRecognizer { func swipeMultiplier(maxTranslation: CGFloat) -> CGFloat { let endLocation = projectedLocation(decelerationRate: .fast) - guard endLocation.y.sign == .plus else { // user swipe up after try dismiss + guard endLocation.y.sign == .plus else { // user swipe up after try dismiss return 1 } - return max(0.3, min(1, abs(maxTranslation / endLocation.y))) // when calculate speed for dismiss animation make range 0.3...1 for multiplier + return max(0.3, min(1, abs(maxTranslation / endLocation.y))) // when calculate speed for dismiss animation make range 0.3...1 for multiplier } - + func incrementToBottom(maxTranslation: CGFloat) -> CGFloat { - let translation = self.translation(in: view).y + let translation = translation(in: view).y setTranslation(.zero, in: nil) - + let percentIncrement = translation / maxTranslation return percentIncrement } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/Extensions.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/Extensions.swift index 90b6b92fe2..bc53adfeb0 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/Extensions.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ActionSheet/Extensions.swift @@ -1,18 +1,16 @@ -import UIKit import SwiftUI +import UIKit -extension UIViewController { - - public var toBottomSheet: UIViewController { +public extension UIViewController { + var toBottomSheet: UIViewController { ActionSheetControllerNew(content: self, configuration: ActionSheetConfiguration(style: .sheet)) } - public var toAlert: UIViewController { + var toAlert: UIViewController { ActionSheetControllerNew(content: self, configuration: ActionSheetConfiguration(style: .alert)) } - public func toActionSheet(configuration: ActionSheetConfiguration) -> UIViewController { + func toActionSheet(configuration: ActionSheetConfiguration) -> UIViewController { ActionSheetControllerNew(content: self, configuration: configuration) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/AmountDecimalParser.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/AmountDecimalParser.swift index db73a6f8a8..7f0c847d14 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/AmountDecimalParser.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/AmountDecimalParser.swift @@ -1,20 +1,17 @@ import Foundation class AmountDecimalParser { - private static let formatter: NumberFormatter = { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.usesGroupingSeparator = false return formatter }() - } extension AmountDecimalParser { - func parseAnyDecimal(from string: String?) -> Decimal? { - if let string = string { + if let string { for localeIdentifier in Locale.availableIdentifiers { Self.formatter.locale = Locale(identifier: localeIdentifier) if Self.formatter.number(from: "0\(string)") == nil { @@ -29,5 +26,4 @@ extension AmountDecimalParser { } return nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/BottomGradientHolder.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/BottomGradientHolder.swift index 01efa52d37..f3d081a454 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/BottomGradientHolder.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/BottomGradientHolder.swift @@ -1,6 +1,6 @@ -import UIKit -import UIExtensions import SnapKit +import UIExtensions +import UIKit protocol IHeightAwareView { var height: CGFloat { get } @@ -32,7 +32,8 @@ class BottomGradientHolder: GradientView { stackView.spacing = .margin16 } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -49,8 +50,9 @@ class BottomGradientHolder: GradientView { } // try to avoid case, when bottom holder bind to tableview but keyboardViewController rewrite insets (ChooseWatchVC) if let keyboardAwareViewController, - keyboardAwareViewController.accessoryView != self { - keyboardAwareViewController.additionalInsetsOnlyForClosedKeyboard = true // add bottom height only when closed keyboard + keyboardAwareViewController.accessoryView != self + { + keyboardAwareViewController.additionalInsetsOnlyForClosedKeyboard = true // add bottom height only when closed keyboard keyboardAwareViewController.additionalContentInsets = .init(top: 0, left: 0, bottom: insets.top, right: 0) } else { // otherwise just setup insets tableView.contentInset.bottom = insets.top @@ -65,17 +67,16 @@ class BottomGradientHolder: GradientView { // we must use self size as inset when keyboard is closed if it's keyboardAwareViewController // only when bottom view is not accessory view (not handling automatic) if let keyboardAwareViewController, - keyboardAwareViewController.accessoryView != self { - keyboardAwareViewController.additionalInsetsOnlyForClosedKeyboard = true // add bottom height only when closed keyboard - keyboardAwareViewController.additionalContentInsets = .init(top: 0, left: 0, bottom: height, right: 0) + keyboardAwareViewController.accessoryView != self + { + keyboardAwareViewController.additionalInsetsOnlyForClosedKeyboard = true // add bottom height only when closed keyboard + keyboardAwareViewController.additionalContentInsets = .init(top: 0, left: 0, bottom: height, right: 0) } } } - } extension BottomGradientHolder { - override func addSubview(_ view: UIView) { guard let position else { fatalError("Before add views need to set position by add(to:_) method") @@ -84,16 +85,15 @@ extension BottomGradientHolder { stackView.layoutIfNeeded() if position == .floating { - remakeConstraints() // update constraints only for floating holder + remakeConstraints() // update constraints only for floating holder } } - func add(to viewController: UIViewController, under tableView: UITableView? = nil) { viewController.view.addSubview(self) if let viewController = viewController as? KeyboardAwareViewController { keyboardAwareViewController = viewController - } // we need to handle additionalInsets when working with keyboardAware controller + } // we need to handle additionalInsets when working with keyboardAware controller remakeConstraints(tableView: tableView) } @@ -101,14 +101,11 @@ extension BottomGradientHolder { override var height: CGFloat { insets.height + stackHeight } - } extension BottomGradientHolder { - enum Position { case bottom case floating } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Caution.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Caution.swift index ce608b8d2e..a87d4bb0a3 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Caution.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Caution.swift @@ -68,8 +68,8 @@ class TitledCaution: Equatable { static func == (lhs: TitledCaution, rhs: TitledCaution) -> Bool { lhs.title == rhs.title && - lhs.text == rhs.text && - lhs.type == rhs.type + lhs.text == rhs.text && + lhs.type == rhs.type } } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/CellComponent.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/CellComponent.swift index a5b4af34a2..0e3e2166ec 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/CellComponent.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/CellComponent.swift @@ -1,222 +1,221 @@ -import UIKit -import ThemeKit -import SectionsTableView import ComponentKit import MarketKit +import SectionsTableView +import ThemeKit +import UIKit struct CellComponent { - static func actionTitleRow(tableView: SectionsTableView, rowInfo: RowInfo, iconName: String?, iconDimmed: Bool, title: String, value: String) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .image24 { component in - if let iconName = iconName { - component.isHidden = false - component.imageView.image = UIImage(named: iconName)?.withTintColor(iconDimmed ? .themeGray : .themeLeah) - } else { - component.isHidden = true - } - }, - .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = title - component.setContentCompressionResistancePriority(.required, for: .horizontal) - }, - .text { component in - component.font = .subhead1 - component.textColor = .themeGray - component.lineBreakMode = .byTruncatingMiddle - component.text = value + rootElement: .hStack([ + .image24 { component in + if let iconName { + component.isHidden = false + component.imageView.image = UIImage(named: iconName)?.withTintColor(iconDimmed ? .themeGray : .themeLeah) + } else { + component.isHidden = true } - ]), - tableView: tableView, - id: "action-\(rowInfo.index)", - hash: "action-\(value)", - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) - } + }, + .text { component in + component.font = .body + component.textColor = .themeLeah + component.text = title + component.setContentCompressionResistancePriority(.required, for: .horizontal) + }, + .text { component in + component.font = .subhead1 + component.textColor = .themeGray + component.lineBreakMode = .byTruncatingMiddle + component.text = value + }, + ]), + tableView: tableView, + id: "action-\(rowInfo.index)", + hash: "action-\(value)", + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + } ) } - static func amountRow(tableView: SectionsTableView, rowInfo: RowInfo, iconUrl: String?, iconPlaceholderImageName: String, coinAmount: String, currencyAmount: String?, type: AmountType, action: (() -> ())? = nil) -> RowProtocol { + static func amountRow(tableView: SectionsTableView, rowInfo: RowInfo, iconUrl: String?, iconPlaceholderImageName: String, coinAmount: String, currencyAmount: String?, type: AmountType, action: (() -> Void)? = nil) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .image32 { (component: ImageComponent) -> () in - component.setImage(urlString: iconUrl, placeholder: UIImage(named: iconPlaceholderImageName)) - }, - .text { (component: TextComponent) -> () in - component.font = type.textFont - component.textColor = type.textColor - component.lineBreakMode = .byTruncatingMiddle - component.text = coinAmount - }, - .text { (component: TextComponent) -> () in - component.isHidden = currencyAmount == nil - component.font = .subhead2 - component.textColor = .themeGray - component.lineBreakMode = .byTruncatingMiddle - component.text = currencyAmount - } - ]), - tableView: tableView, - id: "amount-\(rowInfo.index)", - hash: "amount-\(coinAmount)-\(currencyAmount ?? "")", - height: .heightCell56, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + rootElement: .hStack([ + .image32 { (component: ImageComponent) in + component.setImage(urlString: iconUrl, placeholder: UIImage(named: iconPlaceholderImageName)) }, - action: action + .text { (component: TextComponent) in + component.font = type.textFont + component.textColor = type.textColor + component.lineBreakMode = .byTruncatingMiddle + component.text = coinAmount + }, + .text { (component: TextComponent) in + component.isHidden = currencyAmount == nil + component.font = .subhead2 + component.textColor = .themeGray + component.lineBreakMode = .byTruncatingMiddle + component.text = currencyAmount + }, + ]), + tableView: tableView, + id: "amount-\(rowInfo.index)", + hash: "amount-\(coinAmount)-\(currencyAmount ?? "")", + height: .heightCell56, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + }, + action: action ) } - static func nftAmountRow(tableView: SectionsTableView, rowInfo: RowInfo, iconUrl: String?, iconPlaceholderImageName: String, nftAmount: String, type: AmountType, onTapOpenNft: (() -> ())?) -> RowProtocol { + static func nftAmountRow(tableView: SectionsTableView, rowInfo: RowInfo, iconUrl: String?, iconPlaceholderImageName: String, nftAmount: String, type: AmountType, onTapOpenNft: (() -> Void)?) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .image32 { component in - component.imageView.kf.setImage(with: iconUrl.flatMap { URL(string: $0) }, placeholder: UIImage(named: iconPlaceholderImageName), options: [.onlyLoadFirstFrame, .transition(.fade(0.5))]) - component.imageView.cornerRadius = .cornerRadius4 - component.imageView.contentMode = .scaleAspectFill - }, - .text { component in - component.font = type.textFont - component.textColor = type.textColor - component.lineBreakMode = .byTruncatingMiddle - component.text = nftAmount - } - ]), - tableView: tableView, - id: "nft-amount-\(rowInfo.index)", - hash: "\(nftAmount)", - height: .heightCell48, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + rootElement: .hStack([ + .image32 { component in + component.imageView.kf.setImage(with: iconUrl.flatMap { URL(string: $0) }, placeholder: UIImage(named: iconPlaceholderImageName), options: [.onlyLoadFirstFrame, .transition(.fade(0.5))]) + component.imageView.cornerRadius = .cornerRadius4 + component.imageView.contentMode = .scaleAspectFill + }, + .text { component in + component.font = type.textFont + component.textColor = type.textColor + component.lineBreakMode = .byTruncatingMiddle + component.text = nftAmount }, - action: onTapOpenNft + ]), + tableView: tableView, + id: "nft-amount-\(rowInfo.index)", + hash: "\(nftAmount)", + height: .heightCell48, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + }, + action: onTapOpenNft ) } static func doubleAmountRow(tableView: SectionsTableView, rowInfo: RowInfo, title: String, coinValue: String, currencyValue: String?) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .text { (component: TextComponent) -> () in + rootElement: .hStack([ + .text { (component: TextComponent) in + component.font = .subhead2 + component.textColor = .themeGray + component.text = title + }, + .vStackCentered([ + .text { (component: TextComponent) in component.font = .subhead2 + component.textColor = .themeLeah + component.textAlignment = .right + component.text = coinValue + }, + .margin(1), + .text { (component: TextComponent) in + component.font = .caption component.textColor = .themeGray - component.text = title + component.textAlignment = .right + component.text = currencyValue }, - .vStackCentered([ - .text { (component: TextComponent) -> () in - component.font = .subhead2 - component.textColor = .themeLeah - component.textAlignment = .right - component.text = coinValue - }, - .margin(1), - .text { (component: TextComponent) -> () in - component.font = .caption - component.textColor = .themeGray - component.textAlignment = .right - component.text = currencyValue - } - ]) ]), - tableView: tableView, - id: "double-amount-\(rowInfo.index)", - hash: "double-amount-\(coinValue)-\(currencyValue ?? "-")", - height: .heightDoubleLineCell, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) - } + ]), + tableView: tableView, + id: "double-amount-\(rowInfo.index)", + hash: "double-amount-\(coinValue)-\(currencyValue ?? "-")", + height: .heightDoubleLineCell, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + } ) } - static func fromToRow(tableView: UITableView, rowInfo: RowInfo, title: String, value: String, valueTitle: String?, onAddToContact: (() -> ())? = nil) -> RowProtocol { + static func fromToRow(tableView: UITableView, rowInfo: RowInfo, title: String, value: String, valueTitle _: String?, onAddToContact: (() -> Void)? = nil) -> RowProtocol { let backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence let titleFont: UIFont = .subhead2 let valueFont: UIFont = .subhead1 let inContact = onAddToContact != nil return CellBuilderNew.row( - rootElement: .hStack([ - .text { component in - component.font = titleFont - component.textColor = .themeGray - component.text = title - component.setContentCompressionResistancePriority(.required, for: .horizontal) - }, - .text { component in - component.font = valueFont - component.textColor = .themeLeah - component.text = value - component.textAlignment = .right - component.numberOfLines = 0 - }, - .secondaryCircleButton { component in - component.button.set(image: UIImage(named: "user_plus_20")) - component.isHidden = onAddToContact == nil - component.onTap = { - onAddToContact?() - } - }, - .secondaryCircleButton { component in - component.button.set(image: UIImage(named: "copy_20")) - component.onTap = { - CopyHelper.copyAndNotify(value: value) - } + rootElement: .hStack([ + .text { component in + component.font = titleFont + component.textColor = .themeGray + component.text = title + component.setContentCompressionResistancePriority(.required, for: .horizontal) + }, + .text { component in + component.font = valueFont + component.textColor = .themeLeah + component.text = value + component.textAlignment = .right + component.numberOfLines = 0 + }, + .secondaryCircleButton { component in + component.button.set(image: UIImage(named: "user_plus_20")) + component.isHidden = onAddToContact == nil + component.onTap = { + onAddToContact?() } - ]), - tableView: tableView, - id: "from-to-\(rowInfo.index)", - hash: value + inContact.description + rowInfo.description, - dynamicHeight: { containerWidth in - CellBuilderNew.height( - containerWidth: containerWidth, - backgroundStyle: backgroundStyle, - text: value, - font: valueFont, - elements: [ - .fixed(width: TextComponent.width(font: titleFont, text: title)), - .multiline, - .margin8, - .fixed(width: SecondaryCircleButton.size) - ] - ) }, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) - } + .secondaryCircleButton { component in + component.button.set(image: UIImage(named: "copy_20")) + component.onTap = { + CopyHelper.copyAndNotify(value: value) + } + }, + ]), + tableView: tableView, + id: "from-to-\(rowInfo.index)", + hash: value + inContact.description + rowInfo.description, + dynamicHeight: { containerWidth in + CellBuilderNew.height( + containerWidth: containerWidth, + backgroundStyle: backgroundStyle, + text: value, + font: valueFont, + elements: [ + .fixed(width: TextComponent.width(font: titleFont, text: title)), + .multiline, + .margin8, + .fixed(width: SecondaryCircleButton.size), + ] + ) + }, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + } ) } - static func valueRow(tableView: UITableView, rowInfo: RowInfo, iconName: String?, title: String, value: String, type: ValueType = .regular) -> RowProtocol { + static func valueRow(tableView: UITableView, rowInfo: RowInfo, iconName _: String?, title _: String, value: String, type _: ValueType = .regular) -> RowProtocol { CellBuilder.row( - elements: [.image20, .text, .text], - tableView: tableView, - id: "from-to-\(rowInfo.index)", - hash: value, - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) - } + elements: [.image20, .text, .text], + tableView: tableView, + id: "from-to-\(rowInfo.index)", + hash: value, + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + } ) } static func valueRow(tableView: SectionsTableView, rowInfo: RowInfo, iconName: String?, title: String, value: String, type: ValueType = .regular) -> RowProtocol { tableView.universalRow48( - id: "value-\(rowInfo.index)", - image: iconName.flatMap { UIImage(named: $0)?.withTintColor(.themeGray) }.map { .local($0) }, - title: .subhead2(title), - value: .subhead1(value, color: type.textColor), - hash: value, - isFirst: rowInfo.isFirst, - isLast: rowInfo.isLast + id: "value-\(rowInfo.index)", + image: iconName.flatMap { UIImage(named: $0)?.withTintColor(.themeGray) }.map { .local($0) }, + title: .subhead2(title), + value: .subhead1(value, color: type.textColor), + hash: value, + isFirst: rowInfo.isFirst, + isLast: rowInfo.isLast ) } - static func blockchainAddress(tableView: UITableView, rowInfo: RowInfo, imageUrl: String, title: String, value: String, editType: EditType, action: (()->())? = nil) -> RowProtocol { + static func blockchainAddress(tableView: UITableView, rowInfo: RowInfo, imageUrl: String, title: String, value: String, editType: EditType, action: (() -> Void)? = nil) -> RowProtocol { let backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence let titleFont: UIFont = .subhead1 let valueFont: UIFont = .subhead2 @@ -225,47 +224,46 @@ struct CellComponent { let editColor: UIColor = editType == .original ? .themeGray : .themeJacob return CellBuilderNew.row( - rootElement: .hStack([ - .imageElement(image: .url(imageUrl, placeholder: "placeholder_rectangle_32"), size: .image32), - .vStackCentered([ - .textElement(text: .subhead1(title), parameters: .allCompression), - .margin(titleValueMargin), - .textElement(text: .subhead2(value), parameters: .multiline) - ]), - .imageElement(image: showEdit ? .local(UIImage(named: "edit_20")?.withTintColor(editColor)) : nil, size: .image20) + rootElement: .hStack([ + .imageElement(image: .url(imageUrl, placeholder: "placeholder_rectangle_32"), size: .image32), + .vStackCentered([ + .textElement(text: .subhead1(title), parameters: .allCompression), + .margin(titleValueMargin), + .textElement(text: .subhead2(value), parameters: .multiline), ]), - tableView: tableView, - id: "from-to-\(rowInfo.index)", - hash: title + value, - autoDeselect: action != nil, - dynamicHeight: { containerWidth in - var elements: [CellBuilderNew.LayoutElement] = [ - .fixed(width: .iconSize32), - .multiline - ] + .imageElement(image: showEdit ? .local(UIImage(named: "edit_20")?.withTintColor(editColor)) : nil, size: .image20), + ]), + tableView: tableView, + id: "from-to-\(rowInfo.index)", + hash: title + value, + autoDeselect: action != nil, + dynamicHeight: { containerWidth in + var elements: [CellBuilderNew.LayoutElement] = [ + .fixed(width: .iconSize32), + .multiline, + ] - if showEdit { - elements.append(.fixed(width: .iconSize20)) - } + if showEdit { + elements.append(.fixed(width: .iconSize20)) + } - let height = CellBuilderNew.height( - containerWidth: containerWidth, - backgroundStyle: backgroundStyle, - text: value, - font: valueFont, - verticalPadding: .margin12, - elements: elements - ) + let height = CellBuilderNew.height( + containerWidth: containerWidth, + backgroundStyle: backgroundStyle, + text: value, + font: valueFont, + verticalPadding: .margin12, + elements: elements + ) - return height + titleFont.lineHeight + titleValueMargin - }, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) - }, - action: action + return height + titleFont.lineHeight + titleValueMargin + }, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: rowInfo.isFirst, isLast: rowInfo.isLast) + }, + action: action ) } - } struct RowInfo { @@ -288,7 +286,6 @@ struct RowInfo { var description: String { index.description + isFirst.description + isLast.description } - } enum AmountType { @@ -326,7 +323,6 @@ enum AmountType { case .secondary: return .themeGray } } - } enum EditType { @@ -347,5 +343,4 @@ enum ValueType { case .alert: return .themeLucian } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AdditionalDataCellNew.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AdditionalDataCellNew.swift index aafdf1e76a..70e0ced964 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AdditionalDataCellNew.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AdditionalDataCellNew.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class AdditionalDataCellNew: UITableViewCell { private let titleLabel = UILabel() @@ -59,5 +59,4 @@ class AdditionalDataCellNew: UITableViewCell { var cellHeight: CGFloat { isVisible ? 29 : 0 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AddressInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AddressInputCell.swift index 93ab4c3096..7040de8cf4 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AddressInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AddressInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class AddressInputCell: UITableViewCell { private let addressInputView = AddressInputView() @@ -17,14 +17,13 @@ class AddressInputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension AddressInputCell { - var inputPlaceholder: String? { get { addressInputView.inputPlaceholder } set { addressInputView.inputPlaceholder = newValue } @@ -57,32 +56,32 @@ extension AddressInputCell { set { addressInputView.showContacts = newValue } } - var onTapContacts: (() -> ())? { + var onTapContacts: (() -> Void)? { get { addressInputView.onTapContacts } set { addressInputView.onTapContacts = newValue } } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { addressInputView.onChangeText } set { addressInputView.onChangeText = newValue } } - var onFetchText: ((String?) -> ())? { + var onFetchText: ((String?) -> Void)? { get { addressInputView.onFetchText } set { addressInputView.onFetchText = newValue } } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { addressInputView.onChangeEditing } set { addressInputView.onChangeEditing = newValue } } - var onOpenViewController: ((UIViewController) -> ())? { + var onOpenViewController: ((UIViewController) -> Void)? { get { addressInputView.onOpenViewController } set { addressInputView.onOpenViewController = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { addressInputView.onChangeHeight } set { addressInputView.onChangeHeight = newValue } } @@ -90,5 +89,4 @@ extension AddressInputCell { func height(containerWidth: CGFloat) -> CGFloat { addressInputView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertItemCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertItemCell.swift index c59c5798c8..3e9c1738f5 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertItemCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertItemCell.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit import ComponentKit +import ThemeKit +import UIKit class AlertItemCell: BaseThemeCell { private let button = UIButton() - var onSelect: (() -> ())? + var onSelect: (() -> Void)? override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -27,7 +27,8 @@ class AlertItemCell: BaseThemeCell { button.addTarget(self, action: #selector(onTapButton), for: .touchUpInside) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -52,5 +53,4 @@ class AlertItemCell: BaseThemeCell { button.isSelected = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertTitleCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertTitleCell.swift index e1918a5f9a..ae8718ff02 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertTitleCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AlertTitleCell.swift @@ -22,12 +22,12 @@ class AlertTitleCell: UITableViewCell { label.textAlignment = .center } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func bind(text: String?) { label.text = text } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AmountInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AmountInputCell.swift index 2f387204d2..1e87606335 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AmountInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/AmountInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class AmountInputCell: UITableViewCell { private let formValidatedView: FormValidatedView @@ -21,18 +21,17 @@ class AmountInputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } override func becomeFirstResponder() -> Bool { formAmountInputView.becomeFirstResponder() } - } extension AmountInputCell { - var cellHeight: CGFloat { formAmountInputView.viewHeight } @@ -40,5 +39,4 @@ extension AmountInputCell { func set(cautionType: CautionType?) { formValidatedView.set(cautionType: cautionType) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/BrandFooterCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/BrandFooterCell.swift index 8aeced64c0..8a73999520 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/BrandFooterCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/BrandFooterCell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class BrandFooterCell: UITableViewCell { private let brandFooterView = BrandFooterView() @@ -17,7 +17,8 @@ class BrandFooterCell: UITableViewCell { } } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -25,13 +26,10 @@ class BrandFooterCell: UITableViewCell { get { brandFooterView.title } set { brandFooterView.title = newValue } } - } extension BrandFooterCell { - static func height(containerWidth: CGFloat, title: String) -> CGFloat { BrandFooterView.height(containerWidth: containerWidth, title: title) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/CheckboxCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/CheckboxCell.swift index cf7f875cc9..33b3cb69ae 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/CheckboxCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/CheckboxCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import ComponentKit +import ThemeKit +import UIKit class CheckboxCell: BaseSelectableThemeCell { private let checkBoxView = CheckboxView() @@ -16,7 +16,8 @@ class CheckboxCell: BaseSelectableThemeCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -26,13 +27,10 @@ class CheckboxCell: BaseSelectableThemeCell { checkBoxView.checked = checked } - } extension CheckboxCell { - static func height(containerWidth: CGFloat, text: String, backgroundStyle: BackgroundStyle) -> CGFloat { - CheckboxView.height(containerWidth: containerWidth, text: text, insets: Self.margin(backgroundStyle: backgroundStyle)) + CheckboxView.height(containerWidth: containerWidth, text: text, insets: margin(backgroundStyle: backgroundStyle)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DescriptionCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DescriptionCell.swift index 3810018444..fb63bce170 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DescriptionCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DescriptionCell.swift @@ -24,17 +24,15 @@ class DescriptionCell: UITableViewCell { label.textColor = .themeBran } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension DescriptionCell { - static func height(containerWidth: CGFloat, text: String, font: UIFont? = nil, ignoreBottomMargin: Bool = false) -> CGFloat { let textHeight = text.height(forContainerWidth: containerWidth - 2 * horizontalPadding, font: font ?? Self.font) return textHeight + (ignoreBottomMargin ? 1 : 2) * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DropDownListCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DropDownListCell.swift index 6d8e8bdb85..ad65060015 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DropDownListCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/DropDownListCell.swift @@ -1,8 +1,8 @@ -import UIKit -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift import ThemeKit +import UIKit protocol IDropDownListViewModel { var selectedItemDriver: Driver { get } @@ -13,7 +13,7 @@ class DropDownListCell: BaseSelectableThemeCell { private let viewModel: IDropDownListViewModel private let title: String - var showList: (() -> ())? = nil + var showList: (() -> Void)? = nil init(viewModel: IDropDownListViewModel, title: String) { self.viewModel = viewModel @@ -40,12 +40,12 @@ class DropDownListCell: BaseSelectableThemeCell { component.onTap = { [weak self] in self?.showList?() } - } + }, ])) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FeeCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FeeCell.swift index 99abf9f165..c00bee9e97 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FeeCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FeeCell.swift @@ -1,8 +1,8 @@ -import UIKit -import RxSwift -import RxCocoa import ComponentKit +import RxCocoa +import RxSwift import ThemeKit +import UIKit protocol IFeeViewModel { var valueDriver: Driver { get } @@ -19,7 +19,7 @@ class FeeCell: BaseThemeCell { private var value: FeeCell.Value? private var spinnerVisible: Bool = false - var onOpenInfo: (() -> ())? = nil + var onOpenInfo: (() -> Void)? = nil init(viewModel: IFeeViewModel, title: String, showInfoIcon: Bool = true, isFirst: Bool = true, isLast: Bool = true) { self.viewModel = viewModel @@ -43,7 +43,8 @@ class FeeCell: BaseThemeCell { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -60,7 +61,7 @@ class FeeCell: BaseThemeCell { } }, .margin0, - .text { _ in } + .text { _ in }, ]) } else { titleElements.append( @@ -70,39 +71,39 @@ class FeeCell: BaseThemeCell { let valueElements: [CellBuilderNew.CellElement] = [ .vStackCentered([ - .text({ [weak self] component in + .text { [weak self] component in if let value = self?.value, case let .regular(text, _) = value { component.font = .subhead1 component.textColor = .themeLeah component.text = text component.textAlignment = .right } - }), + }, .margin(1), - .text({ [weak self] component in + .text { [weak self] component in if let value = self?.value, case let .regular(_, secondaryText) = value { component.font = .caption component.textColor = .themeGray component.text = secondaryText ?? "---" component.textAlignment = .right } - }), - ], { [weak self] component in + }, + ]) { [weak self] component in if let value = self?.value, case .regular = value { component.isHidden = false } else { component.isHidden = true } - }), - .text({ [weak self] component in + }, + .text { [weak self] component in switch self?.value { - case .error(let text): + case let .error(text): component.isHidden = false component.font = .subhead1 component.textColor = .themeLucian component.text = text component.textAlignment = .right - case .disabled(let text): + case let .disabled(text): component.isHidden = false component.font = .subhead1 component.textColor = .themeGray @@ -111,19 +112,17 @@ class FeeCell: BaseThemeCell { default: component.isHidden = true } - }), + }, .spinner20 { [weak self] component in component.isHidden = !(self?.spinnerVisible ?? false) - } + }, ] CellBuilderNew.buildStatic(cell: self, rootElement: .hStack(titleElements + valueElements)) } - } extension FeeCell { - enum Value { case disabled(text: String) case regular(text: String, secondaryText: String?) @@ -137,5 +136,4 @@ extension FeeCell { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FormCautionCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FormCautionCell.swift index 75b051a863..6528d0576a 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FormCautionCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/FormCautionCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class FormCautionCell: UITableViewCell { private let cautionView = FormCautionView() @@ -18,19 +18,18 @@ class FormCautionCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension FormCautionCell { - func set(caution: Caution?) { cautionView.set(caution: caution) } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { cautionView.onChangeHeight } set { cautionView.onChangeHeight = newValue } } @@ -38,5 +37,4 @@ extension FormCautionCell { func height(containerWidth: CGFloat) -> CGFloat { cautionView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/HighlightedDescriptionCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/HighlightedDescriptionCell.swift index f9be8f5a06..04fcfd9ae8 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/HighlightedDescriptionCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/HighlightedDescriptionCell.swift @@ -1,7 +1,7 @@ -import UIKit -import RxSwift -import RxRelay import RxCocoa +import RxRelay +import RxSwift +import UIKit class HighlightedDescriptionCell: UITableViewCell { static let horizontalMargin: CGFloat = .margin16 @@ -61,8 +61,8 @@ class HighlightedDescriptionCell: UITableViewCell { setNeedsLayout() } - - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -77,17 +77,15 @@ class HighlightedDescriptionCell: UITableViewCell { hiddenStateRelay.accept(newValue == nil) } } - } extension HighlightedDescriptionCell { - var hiddenStateDriver: Driver { hiddenStateRelay.asDriver() } func height(containerWidth: CGFloat) -> CGFloat { - guard let descriptionText = descriptionText else { + guard let descriptionText else { return 0 } @@ -99,5 +97,4 @@ extension HighlightedDescriptionCell { let descriptionViewHeight = HighlightedDescriptionView.height(containerWidth: descriptionViewWidth, text: text) return descriptionViewHeight + (ignoreBottomMargin ? 0 : 1) * defaultVerticalMargin + (ignoreTopMargin ? 0 : 1) * topVerticalMargin } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ImageCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ImageCell.swift index 6e6b5faa2f..00444addd2 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ImageCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ImageCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit import ComponentKit import SnapKit +import ThemeKit +import UIKit class ImageCell: UITableViewCell { private static let horizontalPadding: CGFloat = .margin16 @@ -21,7 +21,8 @@ class ImageCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -29,17 +30,14 @@ class ImageCell: UITableViewCell { get { customImageView.image } set { customImageView.image = newValue } } - } extension ImageCell { - static func height(containerWidth: CGFloat, imageSize: CGSize? = nil) -> CGFloat { - guard let imageSize = imageSize else { - return max(0, containerWidth - 2 * Self.horizontalPadding) + guard let imageSize else { + return max(0, containerWidth - 2 * horizontalPadding) } return imageSize.height } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/InputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/InputCell.swift index 34587a1af9..bbd77d7da0 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/InputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/InputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class InputCell: UITableViewCell { private let anInputView: InputView @@ -18,18 +18,17 @@ class InputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } override func becomeFirstResponder() -> Bool { anInputView.becomeFirstResponder() } - } extension InputCell { - var inputPlaceholder: String? { get { anInputView.inputPlaceholder } set { anInputView.inputPlaceholder = newValue } @@ -69,17 +68,17 @@ extension InputCell { anInputView.set(cautionType: cautionType) } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { anInputView.onChangeText } set { anInputView.onChangeText = newValue } } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { anInputView.onChangeEditing } set { anInputView.onChangeEditing = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { anInputView.onChangeHeight } set { anInputView.onChangeHeight = newValue } } @@ -92,5 +91,4 @@ extension InputCell { func height(containerWidth: CGFloat) -> CGFloat { anInputView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/LogoHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/LogoHeaderCell.swift index c6afc2605e..7898830cc6 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/LogoHeaderCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/LogoHeaderCell.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class LogoHeaderCell: UITableViewCell { private static let logoSize: CGFloat = 72 @@ -79,13 +79,10 @@ class LogoHeaderCell: UITableViewCell { func set(imageUrl: String?) { logoImageView.kf.setImage(with: imageUrl.flatMap { URL(string: $0) }, placeholder: UIImage(named: "placeholder_rectangle_32")) } - } extension LogoHeaderCell { - static var height: CGFloat { logoSize + verticalMargin * 2 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicInputCell.swift index dd1c1588b4..41126c6752 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicInputCell.swift @@ -1,10 +1,10 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class MnemonicInputCell: TextInputCell { - var onChangeMnemonicText: ((String, Int) -> ())? - var onChangeEntering: (() -> ())? + var onChangeMnemonicText: ((String, Int) -> Void)? + var onChangeEntering: (() -> Void)? private(set) var entering = false { didSet { @@ -39,15 +39,13 @@ class MnemonicInputCell: TextInputCell { super.set(text: text) onChangeMnemonicText?(text, text.count) } - } extension MnemonicInputCell { - func set(invalidRanges: [NSRange]) { let attributedString = NSMutableAttributedString(string: textView.text, attributes: [ .foregroundColor: textViewTextColor, - .font: textViewFont + .font: textViewFont, ]) for range in invalidRanges { @@ -78,5 +76,4 @@ extension MnemonicInputCell { onChangeMnemonicText?(text, cursorOffset) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicPhraseCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicPhraseCell.swift index 4d2d482248..2c94ed9e54 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicPhraseCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicPhraseCell.swift @@ -1,8 +1,8 @@ -import UIKit -import ThemeKit -import SnapKit -import ComponentKit import CollectionViewCenteredFlowLayout +import ComponentKit +import SnapKit +import ThemeKit +import UIKit class MnemonicPhraseCell: BaseThemeCell { private static let backgroundStyle: BaseThemeCell.BackgroundStyle = .bordered @@ -47,22 +47,21 @@ class MnemonicPhraseCell: BaseThemeCell { hintText.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension MnemonicPhraseCell { - func set(state: State) { switch state { - case .hidden(let hint): + case let .hidden(hint): collectionView.isHidden = true hintText.isHidden = false hintText.text = hint - case .visible(let words): + case let .visible(words): hintText.isHidden = true collectionView.isHidden = false @@ -71,51 +70,43 @@ extension MnemonicPhraseCell { collectionView.layoutIfNeeded() } } - } extension MnemonicPhraseCell: UICollectionViewDataSource { - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + public func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { words.count } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: MnemonicWordCell.self), for: indexPath) } - } extension MnemonicPhraseCell: UICollectionViewDelegate { - - public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + public func collectionView(_: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? MnemonicWordCell { let index = indexPath.item cell.bind(index: index + 1, word: words[index]) } } - } extension MnemonicPhraseCell: UICollectionViewDelegateFlowLayout { - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let index = indexPath.item return MnemonicWordCell.size(index: index + 1, word: words[index]) } - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { Self.itemSpacing } - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + public func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumLineSpacingForSectionAt _: Int) -> CGFloat { Self.lineSpacing } - } extension MnemonicPhraseCell { - static func height(containerWidth: CGFloat, words: [String]) -> CGFloat { let collectionWidth = containerWidth - margin(backgroundStyle: backgroundStyle).width - horizontalPadding * 2 @@ -139,14 +130,11 @@ extension MnemonicPhraseCell { let collectionHeight = CGFloat(lines) * lineHeight + CGFloat(lines - 1) * lineSpacing return collectionHeight + verticalPadding * 2 } - } extension MnemonicPhraseCell { - enum State { case hidden(hint: String) case visible(words: [String]) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicWordCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicWordCell.swift index d9f88b7a10..d676268191 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicWordCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/MnemonicWordCell.swift @@ -1,5 +1,5 @@ -import UIKit import ComponentKit +import UIKit class MnemonicWordCell: UICollectionViewCell { private static let indexFont: UIFont = .subhead1 @@ -33,7 +33,8 @@ class MnemonicWordCell: UICollectionViewCell { wordText.textColor = .themeLeah } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -41,19 +42,16 @@ class MnemonicWordCell: UICollectionViewCell { indexText.text = "\(index)" wordText.text = word } - } extension MnemonicWordCell { - static func size(index: Int, word: String) -> CGSize { let indexSize = "\(index)".size(containerWidth: .greatestFiniteMagnitude, font: indexFont) let wordSize = word.size(containerWidth: .greatestFiniteMagnitude, font: wordFont) return CGSize( - width: indexSize.width + spacing + wordSize.width, - height: max(indexSize.height, wordSize.height) + width: indexSize.width + spacing + wordSize.width, + height: max(indexSize.height, wordSize.height) ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/NftDoubleCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/NftDoubleCell.swift index 800da35b9c..afe3ee7094 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/NftDoubleCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/NftDoubleCell.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class NftDoubleCell: UITableViewCell { private static let horizontalMargin: CGFloat = .margin16 @@ -36,7 +36,7 @@ class NftDoubleCell: UITableViewCell { super.init(coder: aDecoder) } - private func bind(view: NftAssetView, viewItem: ViewItem, onTap: @escaping (ViewItem) -> ()) { + private func bind(view: NftAssetView, viewItem: ViewItem, onTap: @escaping (ViewItem) -> Void) { view.imagePlaceholder = viewItem.name view.name = viewItem.name view.coinPrice = viewItem.coinPrice @@ -46,37 +46,31 @@ class NftDoubleCell: UITableViewCell { view.setImage(url: viewItem.imageUrl) view.onTap = { onTap(viewItem) } } - } extension NftDoubleCell { - - func bind(leftViewItem: ViewItem, rightViewItem: ViewItem?, onTap: @escaping (ViewItem) -> ()) { + func bind(leftViewItem: ViewItem, rightViewItem: ViewItem?, onTap: @escaping (ViewItem) -> Void) { bind(view: leftView, viewItem: leftViewItem, onTap: onTap) - if let rightViewItem = rightViewItem { + if let rightViewItem { rightView.isHidden = false bind(view: rightView, viewItem: rightViewItem, onTap: onTap) } else { rightView.isHidden = true } } - } extension NftDoubleCell { - static func height(containerWidth: CGFloat, isLast: Bool) -> CGFloat { let itemWidth = (containerWidth - horizontalMargin * 3) / 2 let itemHeight = NftAssetView.height(containerWidth: itemWidth) let bottomMargin = isLast ? bottomMarginLast : bottomMarginRegular return topMargin + itemHeight + bottomMargin } - } extension NftDoubleCell { - struct ViewItem { let providerCollectionUid: String? let nftUid: NftUid @@ -91,5 +85,4 @@ extension NftDoubleCell { "\(count ?? "nil")-\(onSale)-\(coinPrice)-\(fiatPrice ?? "nil")" } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PasteInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PasteInputCell.swift index 74ed76e0f5..ac64d9ac59 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PasteInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PasteInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class PasteInputCell: UITableViewCell { private let pasteInputView = PasteInputView() @@ -17,14 +17,13 @@ class PasteInputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension PasteInputCell { - var inputPlaceholder: String? { get { pasteInputView.inputPlaceholder } set { pasteInputView.inputPlaceholder = newValue } @@ -54,22 +53,22 @@ extension PasteInputCell { pasteInputView.set(cautionType: cautionType) } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { pasteInputView.onChangeText } set { pasteInputView.onChangeText = newValue } } - var onFetchText: ((String?) -> ())? { + var onFetchText: ((String?) -> Void)? { get { pasteInputView.onFetchText } set { pasteInputView.onFetchText = newValue } } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { pasteInputView.onChangeEditing } set { pasteInputView.onChangeEditing = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { pasteInputView.onChangeHeight } set { pasteInputView.onChangeHeight = newValue } } @@ -77,5 +76,4 @@ extension PasteInputCell { func height(containerWidth: CGFloat) -> CGFloat { pasteInputView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PlaceholderCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PlaceholderCell.swift index cbfc68138e..840cf0a0c8 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PlaceholderCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PlaceholderCell.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class PlaceholderCell: BaseThemeCell { private let placeholderView = PlaceholderView() @@ -15,7 +15,8 @@ class PlaceholderCell: BaseThemeCell { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -36,5 +37,4 @@ class PlaceholderCell: BaseThemeCell { func removeAllButtons() { placeholderView.removeAllButtons() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PostCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PostCell.swift index 6c78b88c44..bf32c897c0 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PostCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PostCell.swift @@ -1,5 +1,5 @@ -import UIKit import ComponentKit +import UIKit class PostCell: BaseSelectableThemeCell { static let height: CGFloat = 140 @@ -74,5 +74,4 @@ class PostCell: BaseSelectableThemeCell { bodyLabel.numberOfLines = 3 - titleNumberOfLines } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PrimaryButtonCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PrimaryButtonCell.swift index 7ae23b505e..bebccc87d2 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PrimaryButtonCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PrimaryButtonCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import ComponentKit +import ThemeKit +import UIKit class PrimaryButtonCell: UITableViewCell { private static let verticalPadding: CGFloat = .margin16 @@ -8,7 +8,7 @@ class PrimaryButtonCell: UITableViewCell { private let button = PrimaryButton() - var onTap: (() -> ())? + var onTap: (() -> Void)? override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -25,7 +25,8 @@ class PrimaryButtonCell: UITableViewCell { button.addTarget(self, action: #selector(onTapButton), for: .touchUpInside) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -46,5 +47,4 @@ class PrimaryButtonCell: UITableViewCell { func set(style: PrimaryButton.Style) { button.set(style: style) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PsswordInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PsswordInputCell.swift index 7e029fef86..6e06c3c88b 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PsswordInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/PsswordInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class PasswordInputCell: UITableViewCell { private let passwordInputView = PasswordInputView() @@ -17,14 +17,13 @@ class PasswordInputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension PasswordInputCell { - var inputPlaceholder: String? { get { passwordInputView.inputPlaceholder } set { passwordInputView.inputPlaceholder = newValue } @@ -35,12 +34,12 @@ extension PasswordInputCell { set { passwordInputView.inputText = newValue } } - var onTextSecurityChange: ((Bool) -> ())? { + var onTextSecurityChange: ((Bool) -> Void)? { get { passwordInputView.onTextSecurityChange } set { passwordInputView.onTextSecurityChange = newValue } } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { passwordInputView.onChangeText } set { passwordInputView.onChangeText = newValue } } @@ -61,5 +60,4 @@ extension PasswordInputCell { func set(textSecure: Bool) { passwordInputView.set(textSecure: textSecure) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/QrCodeCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/QrCodeCell.swift index daf14286be..f49d28c9ee 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/QrCodeCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/QrCodeCell.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class QrCodeCell: UITableViewCell { private static let horizontalMargin: CGFloat = .margin16 @@ -18,7 +18,7 @@ class QrCodeCell: UITableViewCell { private let tokenImageView = UIImageView() private let label = UILabel() - var onTap: (() -> ())? + var onTap: (() -> Void)? override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -98,7 +98,8 @@ class QrCodeCell: UITableViewCell { label.textColor = .themeGray } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -112,15 +113,12 @@ class QrCodeCell: UITableViewCell { label.text = text } - } extension QrCodeCell { - static func height(containerWidth: CGFloat, text: String) -> CGFloat { let textWidth = containerWidth - 2 * horizontalMargin - 2 * textHorizontalMargin let textHeight = text.height(forContainerWidth: textWidth, font: textFont) return qrCodeTopMargin + qrCodeSize + qrCodeBottomMargin + textHeight + textBottomMargin } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ReadMoreTextCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ReadMoreTextCell.swift index 5af3870acf..0837808747 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ReadMoreTextCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ReadMoreTextCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class ReadMoreTextCell: BaseThemeCell { private static let collapsedHeight: CGFloat = 160 @@ -24,8 +24,8 @@ class ReadMoreTextCell: BaseThemeCell { } } - var onTapLink: ((URL) -> ())? - var onChangeHeight: (() -> ())? + var onTapLink: ((URL) -> Void)? + var onChangeHeight: (() -> Void)? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -68,7 +68,8 @@ class ReadMoreTextCell: BaseThemeCell { collapseButton.addTarget(self, action: #selector(onTapCollapse), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -135,14 +136,11 @@ class ReadMoreTextCell: BaseThemeCell { expandable = true } } - } extension ReadMoreTextCell: UITextViewDelegate { - - public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + public func textView(_: UITextView, shouldInteractWith URL: URL, in _: NSRange, interaction _: UITextItemInteraction) -> Bool { onTapLink?(URL) return true } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressCautionCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressCautionCell.swift index 2f99b49cd5..cf02dfa799 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressCautionCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressCautionCell.swift @@ -1,5 +1,5 @@ -import UIKit import RxSwift +import UIKit class RecipientAddressCautionCell: FormCautionCell { private let viewModel: RecipientAddressViewModel @@ -15,8 +15,8 @@ class RecipientAddressCautionCell: FormCautionCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressInputCell.swift index 726ab5b092..f43c3acdd6 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/RecipientAddressInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import RxSwift import ComponentKit +import RxSwift +import UIKit class RecipientAddressInputCell: AddressInputCell { private let viewModel: RecipientAddressViewModel @@ -37,14 +37,15 @@ class RecipientAddressInputCell: AddressInputCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } private func openContacts() { guard let blockchainType = viewModel.contactBlockchainType, let viewController = ContactBookModule.viewController( - mode: .select(blockchainType, self), - presented: true + mode: .select(blockchainType, self), + presented: true ) else { return } @@ -60,13 +61,10 @@ class RecipientAddressInputCell: AddressInputCell { self.inputText = inputText ?? "" viewModel.onChange(text: inputText) } - } extension RecipientAddressInputCell: ContactBookSelectorDelegate { - func onFetch(address: String) { set(inputText: address) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ResendPastInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ResendPastInputCell.swift index 6396e3bd7c..f8168b3a6b 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ResendPastInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ResendPastInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class ResendPasteInputCell: UITableViewCell { private let view = ResendPasteInputView() @@ -17,14 +17,13 @@ class ResendPasteInputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension ResendPasteInputCell { - var inputPlaceholder: String? { get { view.inputPlaceholder } set { view.inputPlaceholder = newValue } @@ -59,27 +58,27 @@ extension ResendPasteInputCell { view.set(cautionType: cautionType) } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { view.onChangeText } set { view.onChangeText = newValue } } - var onFetchText: ((String?) -> ())? { + var onFetchText: ((String?) -> Void)? { get { view.onFetchText } set { view.onFetchText = newValue } } - var onResend: (() -> ())? { + var onResend: (() -> Void)? { get { view.onResend } set { view.onResend = newValue } } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { view.onChangeEditing } set { view.onChangeEditing = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { view.onChangeHeight } set { view.onChangeHeight = newValue } } @@ -87,5 +86,4 @@ extension ResendPasteInputCell { func height(containerWidth: CGFloat) -> CGFloat { view.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/SecondaryButtonCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/SecondaryButtonCell.swift index ed0d1e859d..73d9ff03ea 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/SecondaryButtonCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/SecondaryButtonCell.swift @@ -1,13 +1,13 @@ -import UIKit -import ThemeKit import ComponentKit +import ThemeKit +import UIKit class SecondaryButtonCell: UITableViewCell { private static let verticalPadding: CGFloat = .margin16 private let button = SecondaryButton() - var onTap: (() -> ())? + var onTap: (() -> Void)? override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -23,7 +23,8 @@ class SecondaryButtonCell: UITableViewCell { button.addTarget(self, action: #selector(onTapButton), for: .touchUpInside) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -44,13 +45,10 @@ class SecondaryButtonCell: UITableViewCell { func set(style: SecondaryButton.Style) { button.set(style: style) } - } extension SecondaryButtonCell { - static func height(style: SecondaryButton.Style) -> CGFloat { SecondaryButton.height(style: style) + 2 * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ShortcutInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ShortcutInputCell.swift index c5915ea3b2..a0be1e4233 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ShortcutInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/ShortcutInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class ShortcutInputCell: UITableViewCell { private let formValidatedView: FormValidatedView @@ -9,7 +9,7 @@ class ShortcutInputCell: UITableViewCell { private var shortcutViews = [InputSecondaryButtonWrapperView]() private let deleteView = InputSecondaryCircleButtonWrapperView() - var onChangeText: ((String?) -> ())? + var onChangeText: ((String?) -> Void)? init() { formValidatedView = FormValidatedView(contentView: inputStackView) @@ -36,7 +36,8 @@ class ShortcutInputCell: UITableViewCell { syncButtonStates() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -59,11 +60,9 @@ class ShortcutInputCell: UITableViewCell { shortcutViews.forEach { view in view.isHidden = false } } } - } extension ShortcutInputCell { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -119,7 +118,7 @@ extension ShortcutInputCell { syncButtonStates() } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { formValidatedView.onChangeHeight } set { formValidatedView.onChangeHeight = newValue } } @@ -132,7 +131,6 @@ extension ShortcutInputCell { func height(containerWidth: CGFloat) -> CGFloat { formValidatedView.height(containerWidth: containerWidth) } - } struct InputShortcut { diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/StackViewCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/StackViewCell.swift index 04fc09f2dc..28010c6c89 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/StackViewCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/StackViewCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class StackViewCell: UITableViewCell { private let stackView = UIStackView() @@ -22,12 +22,12 @@ class StackViewCell: UITableViewCell { stackView.spacing = .margin2x } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func add(view: UIView) { stackView.addArrangedSubview(view) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextCell.swift index 2a47bf28be..5415ab07f0 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextCell.swift @@ -24,7 +24,8 @@ class TextCell: UITableViewCell { label.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -32,14 +33,11 @@ class TextCell: UITableViewCell { get { label.text } set { label.text = newValue } } - } extension TextCell { - static func height(containerWidth: CGFloat, text: String) -> CGFloat { let textHeight = text.height(forContainerWidth: containerWidth - 2 * horizontalPadding, font: font) return textHeight + 2 * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextFieldCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextFieldCell.swift index 110dfa671e..903e704680 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextFieldCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextFieldCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class TextFieldCell: UITableViewCell { private let wrapperView = UIView() @@ -32,7 +32,8 @@ class TextFieldCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -43,11 +44,9 @@ class TextFieldCell: UITableViewCell { func prependSubview(_ view: UIView, customSpacing: CGFloat? = nil) { stackView.prependSubview(view, customSpacing: customSpacing) } - } extension TextFieldCell { - var inputPlaceholder: String? { get { stackView.placeholder } set { stackView.placeholder = newValue } @@ -81,7 +80,7 @@ extension TextFieldCell { func set(cautionType: CautionType?) { let borderColor: UIColor - if let cautionType = cautionType { + if let cautionType { borderColor = cautionType.borderColor } else { borderColor = .themeSteel20 @@ -90,12 +89,12 @@ extension TextFieldCell { wrapperView.layer.borderColor = borderColor.cgColor } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { stackView.onChangeText } set { stackView.onChangeText = newValue } } - var onReturn: (() -> ())? { + var onReturn: (() -> Void)? { get { stackView.onReturn } set { stackView.onReturn = newValue } } @@ -104,5 +103,4 @@ extension TextFieldCell { get { stackView.isValidText } set { stackView.isValidText = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextInputCell.swift index 85cc010183..6ae1d9928a 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TextInputCell.swift @@ -155,7 +155,7 @@ class TextInputCell: UITableViewCell { func set(cautionType: CautionType?) { let borderColor: UIColor - if let cautionType = cautionType { + if let cautionType { borderColor = cautionType.borderColor } else { borderColor = textViewBorderColor diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TitledHighlightedDescriptionCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TitledHighlightedDescriptionCell.swift index d118393423..01309348e9 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TitledHighlightedDescriptionCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/TitledHighlightedDescriptionCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit import ComponentKit import SectionsTableView +import ThemeKit +import UIKit class TitledHighlightedDescriptionCell: BaseThemeCell { private static let horizontalMargin: CGFloat = .margin16 @@ -30,7 +30,8 @@ class TitledHighlightedDescriptionCell: BaseThemeCell { } } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -64,12 +65,12 @@ class TitledHighlightedDescriptionCell: BaseThemeCell { set { descriptionView.titleColor = newValue } } - var onBackgroundButton: (() -> ())? { + var onBackgroundButton: (() -> Void)? { get { descriptionView.onTapBackground } set { descriptionView.onTapBackground = newValue } } - var onCloseButton: (() -> ())? { + var onCloseButton: (() -> Void)? { didSet { descriptionView.onTapClose = onCloseButton descriptionView.closeButtonHidden = onCloseButton == nil @@ -83,22 +84,19 @@ class TitledHighlightedDescriptionCell: BaseThemeCell { titleText = caution.title titleColor = caution.type == .error ? .themeLucian : .themeJacob descriptionText = caution.text - contentBackgroundColor = caution.type == .error ? UIColor(hex: 0xff4820, alpha: 0.2) : .themeYellow20 + contentBackgroundColor = caution.type == .error ? UIColor(hex: 0xFF4820, alpha: 0.2) : .themeYellow20 contentBorderColor = caution.type == .error ? .themeLucian : .themeJacob } func cellHeight(containerWidth: CGFloat) -> CGFloat { isVisible ? Self.height(containerWidth: containerWidth, text: descriptionText ?? "") : 0 } - } extension TitledHighlightedDescriptionCell { - static func height(containerWidth: CGFloat, text: String) -> CGFloat { let descriptionViewWidth = containerWidth - 2 * horizontalMargin let descriptionViewHeight = TitledHighlightedDescriptionView.height(containerWidth: descriptionViewWidth, text: text) return descriptionViewHeight } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataView.swift index ba9517447a..b029195696 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataView.swift @@ -39,7 +39,8 @@ class AdditionalDataView: UIView { valueLabel.font = .subhead2 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -66,7 +67,7 @@ class AdditionalDataView: UIView { } func set(hidden: Bool) { - self.isHidden = hidden + isHidden = hidden snp.updateConstraints { maker in maker.height.equalTo(hidden ? 0 : Self.height) } @@ -82,5 +83,4 @@ class AdditionalDataView: UIView { get { valueLabel.text } set { valueLabel.text = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataWithErrorView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataWithErrorView.swift index d8aa88a3af..976f318c0d 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataWithErrorView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/AdditionalDataWithErrorView.swift @@ -1,5 +1,5 @@ -import UIKit import HUD +import UIKit class AdditionalDataWithErrorView: UIView { private let additionalDataView = AdditionalDataView() @@ -33,7 +33,8 @@ class AdditionalDataWithErrorView: UIView { errorLabel.numberOfLines = 0 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -50,9 +51,7 @@ class AdditionalDataWithErrorView: UIView { errorLabel.text = error } - func setValue(color: UIColor) { additionalDataView.setValue(color: color) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/CheckboxView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/CheckboxView.swift index 6ae7883223..93253d2566 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/CheckboxView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/CheckboxView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import ComponentKit +import ThemeKit +import UIKit class CheckboxView: UIView { private static let checkBoxLeadingMargin: CGFloat = .margin16 @@ -51,7 +51,8 @@ class CheckboxView: UIView { descriptionLabel.textColor = .themeLeah } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -69,16 +70,13 @@ class CheckboxView: UIView { get { !checkBoxImageView.isHidden } set { checkBoxImageView.isHidden = !newValue } } - } extension CheckboxView { - static func height(containerWidth: CGFloat, text: String, insets: UIEdgeInsets = .zero) -> CGFloat { let textWidth = containerWidth - insets.width - checkBoxLeadingMargin - checkBoxSize - textLeadingMargin - textTrailingMargin let textHeight = text.height(forContainerWidth: textWidth, font: textFont) return textHeight + 2 * textVerticalMargin } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/InfoSeparatorHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/InfoSeparatorHeaderView.swift index c2523dd996..868dacfce2 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/InfoSeparatorHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Cells/Views/InfoSeparatorHeaderView.swift @@ -18,8 +18,8 @@ class InfoSeparatorHeaderView: UITableViewHeaderFooterView { separator.backgroundColor = .themeSteel20 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ChartIntervalConverter.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ChartIntervalConverter.swift index 3b58c1f72e..ec6f2169e5 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ChartIntervalConverter.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ChartIntervalConverter.swift @@ -16,5 +16,4 @@ class ChartIntervalConverter { case .year2: return 4 * month } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AddressInputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AddressInputView.swift index f37f28b72e..af88e1855e 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AddressInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AddressInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class AddressInputView: UIView { private let formValidatedView: FormValidatedView @@ -14,10 +14,10 @@ class AddressInputView: UIView { private let scanView = InputSecondaryCircleButtonWrapperView() private let pasteView = InputSecondaryButtonWrapperView(style: .default) - var onChangeText: ((String?) -> ())? - var onFetchText: ((String?) -> ())? - var onOpenViewController: ((UIViewController) -> ())? - var onTapContacts: (() -> ())? + var onChangeText: ((String?) -> Void)? + var onFetchText: ((String?) -> Void)? + var onOpenViewController: ((UIViewController) -> Void)? + var onTapContacts: (() -> Void)? var showContacts: Bool = false { didSet { @@ -69,7 +69,8 @@ class AddressInputView: UIView { syncButtonStates() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -111,11 +112,9 @@ class AddressInputView: UIView { contactView.isHidden = !showContacts } } - } extension AddressInputView { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -146,12 +145,12 @@ extension AddressInputView { stateView.isSpinnerVisible = isLoading } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { inputStackView.onChangeEditing } set { inputStackView.onChangeEditing = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { formValidatedView.onChangeHeight } set { formValidatedView.onChangeHeight = newValue } } @@ -159,5 +158,4 @@ extension AddressInputView { func height(containerWidth: CGFloat) -> CGFloat { formValidatedView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AmountInputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AmountInputView.swift index 4ddd65d704..c5efcb0271 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AmountInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/AmountInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class AmountInputView: UIView { let viewHeight: CGFloat = 85 @@ -21,15 +21,16 @@ class AmountInputView: UIView { syncButtonStates() } } + var clearHidden = false { didSet { syncButtonStates() } } - var onChangeText: ((String?) -> ())? - var onTapMax: (() -> ())? - var onTapSecondary: (() -> ())? + var onChangeText: ((String?) -> Void)? + var onTapMax: (() -> Void)? + var onTapSecondary: (() -> Void)? init(singleLine: Bool = false) { inputStackView = InputStackView(singleLine: singleLine) @@ -102,7 +103,8 @@ class AmountInputView: UIView { syncButtonStates() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -128,11 +130,9 @@ class AmountInputView: UIView { clearView.isHidden = true } } - } extension AmountInputView { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -169,7 +169,6 @@ extension AmountInputView { set { prefixView.textColor = newValue } } - var secondaryButtonText: String? { get { secondaryButton.title(for: .normal) } set { secondaryButton.setTitle(newValue, for: .normal) } @@ -185,18 +184,18 @@ extension AmountInputView { set { secondaryButton.isEnabled = newValue } } - var estimatedVisible: Bool { - get { estimatedView.isHidden } - set { estimatedView.isHidden = !newValue } - } + var estimatedVisible: Bool { + get { estimatedView.isHidden } + set { estimatedView.isHidden = !newValue } + } - var warningText: String? { - get { warningView.text } - set { - warningView.text = newValue - warningView.isHidden = (newValue == nil) - } - } + var warningText: String? { + get { warningView.text } + set { + warningView.text = newValue + warningView.isHidden = (newValue == nil) + } + } var isValidText: ((String) -> Bool)? { get { inputStackView.isValidText } @@ -212,18 +211,15 @@ extension AmountInputView { get { inputStackView.editable } set { inputStackView.editable = newValue } } - } extension AmountInputView: IHeightControlView { // required in FormValidatedView, but not used yet - - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { nil } set {} } - func height(containerWidth: CGFloat) -> CGFloat { + func height(containerWidth _: CGFloat) -> CGFloat { 0 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/BrandFooterView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/BrandFooterView.swift index 9867da9d27..b6105f6686 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/BrandFooterView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/BrandFooterView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class BrandFooterView: UIView { private static let topPadding: CGFloat = .margin12 @@ -36,7 +36,8 @@ class BrandFooterView: UIView { label.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -44,16 +45,13 @@ class BrandFooterView: UIView { get { label.text } set { label.text = newValue } } - } extension BrandFooterView { - static func height(containerWidth: CGFloat, title: String) -> CGFloat { let textWidth = containerWidth - 2 * horizontalPadding let textHeight = title.height(forContainerWidth: textWidth, font: labelFont) return topPadding + textHeight + bottomPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewController.swift index 0d1c4f48b2..9925e6eea3 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewController.swift @@ -1,13 +1,13 @@ -import Combine -import UIKit import Alamofire -import RxSwift -import RxCocoa -import SnapKit +import Combine import ComponentKit import MarketKit +import RxCocoa +import RxSwift import SectionsTableView +import SnapKit import ThemeKit +import UIKit class CoinToggleViewController: ThemeSearchViewController { private let viewModel: ICoinToggleViewModel @@ -25,7 +25,8 @@ class CoinToggleViewController: ThemeSearchViewController { super.init(scrollViews: [tableView]) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -44,9 +45,9 @@ class CoinToggleViewController: ThemeSearchViewController { subscribe(disposeBag, viewModel.viewItemsDriver) { [weak self] in self?.onUpdate(viewItems: $0) } $filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } - .store(in: &cancellables) + .receive(on: DispatchQueue.main) + .sink { [weak self] in self?.viewModel.onUpdate(filter: $0 ?? "") } + .store(in: &cancellables) tableView.buildSections() @@ -54,7 +55,7 @@ class CoinToggleViewController: ThemeSearchViewController { } private func onUpdate(viewItems: [CoinToggleViewModel.ViewItem]) { - let animated = self.viewItems.map { $0.uid } == viewItems.map { $0.uid } + let animated = self.viewItems.map(\.uid) == viewItems.map(\.uid) self.viewItems = viewItems if isLoaded { @@ -65,7 +66,7 @@ class CoinToggleViewController: ThemeSearchViewController { private func elements(viewItem: CoinToggleViewModel.ViewItem, forceToggleOn: Bool? = nil) -> [CellBuilderNew.CellElement] { var elements = [CellBuilderNew.CellElement]() - elements.append(.image32 { (component: ImageComponent) -> () in + elements.append(.image32 { (component: ImageComponent) in component.setImage(urlString: viewItem.imageUrl, placeholder: viewItem.placeholderImageName.flatMap { UIImage(named: $0) }) }) elements.append(.vStackCentered([ @@ -83,14 +84,14 @@ class CoinToggleViewController: ThemeSearchViewController { component.isHidden = viewItem.badge == nil }, .margin0, - .text { _ in } + .text { _ in }, ]), .margin(1), - .text { (component: TextComponent) -> () in + .text { (component: TextComponent) in component.font = .subhead2 component.textColor = .themeGray component.text = viewItem.subtitle - } + }, ])) switch viewItem.state { case let .toggleVisible(enabled, hasSettings, hasInfo): @@ -109,7 +110,7 @@ class CoinToggleViewController: ThemeSearchViewController { self?.viewModel.onTapInfo(uid: viewItem.uid) } }, - .switch { (component: SwitchComponent) -> () in + .switch { (component: SwitchComponent) in if let forceOn = forceToggleOn { component.switchView.setOn(forceOn, animated: true) } else { @@ -119,7 +120,7 @@ class CoinToggleViewController: ThemeSearchViewController { component.onSwitch = { [weak self] enabled in self?.onToggle(viewItem: viewItem, enabled: enabled) } - } + }, ]) default: () } @@ -129,29 +130,29 @@ class CoinToggleViewController: ThemeSearchViewController { private func row(viewItem: CoinToggleViewModel.ViewItem, isLast: Bool) -> RowProtocol { let elements = elements(viewItem: viewItem) - var hash: String = "" - var action: (() -> ())? + var hash = "" + var action: (() -> Void)? switch viewItem.state { case let .toggleVisible(enabled, hasSettings, hasInfo): hash = "coin_\(enabled)_\(hasSettings)_\(hasInfo)_\(isLast)" - case .toggleHidden(let notSupportedReason): + case let .toggleHidden(notSupportedReason): hash = "coin_\(isLast)" action = { [weak self] in self?.onTapToggleHidden(viewItem: viewItem, notSupportedReason: notSupportedReason) } } return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: tableView, - id: "coin_\(viewItem.uid)", - hash: hash, - height: .heightDoubleLineCell, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - }, - action: action + rootElement: .hStack(elements), + tableView: tableView, + id: "coin_\(viewItem.uid)", + hash: hash, + height: .heightDoubleLineCell, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .transparent, isLast: isLast) + }, + action: action ) } @@ -175,24 +176,20 @@ class CoinToggleViewController: ThemeSearchViewController { CellBuilderNew.buildStatic(cell: cell, rootElement: .hStack(elements(viewItem: viewItems[index], forceToggleOn: on))) } - func onTapToggleHidden(viewItem: CoinToggleViewModel.ViewItem, notSupportedReason: String) { - } - + func onTapToggleHidden(viewItem _: CoinToggleViewModel.ViewItem, notSupportedReason _: String) {} } extension CoinToggleViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { [ Section( - id: "coins", - headerState: .margin(height: .margin4), - footerState: .margin(height: .margin32), - rows: viewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, isLast: index == viewItems.count - 1) - } - ) + id: "coins", + headerState: .margin(height: .margin4), + footerState: .margin(height: .margin32), + rows: viewItems.enumerated().map { index, viewItem in + row(viewItem: viewItem, isLast: index == viewItems.count - 1) + } + ), ] } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewModel.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewModel.swift index b57a3e2a73..6f488ece9d 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/CoinToggle/CoinToggleViewModel.swift @@ -1,6 +1,6 @@ -import RxSwift -import RxCocoa import MarketKit +import RxCocoa +import RxSwift protocol ICoinToggleViewModel { var viewItemsDriver: Driver<[CoinToggleViewModel.ViewItem]> { get } @@ -12,8 +12,7 @@ protocol ICoinToggleViewModel { func onUpdate(filter: String) } -class CoinToggleViewModel { - +enum CoinToggleViewModel { struct ViewItem { let uid: String let imageUrl: String @@ -28,5 +27,4 @@ class CoinToggleViewModel { case toggleVisible(enabled: Bool, hasSettings: Bool, hasInfo: Bool) case toggleHidden(notSupportedReason: String) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/DiffLabel.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/DiffLabel.swift index 8691492f3d..3829540436 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/DiffLabel.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/DiffLabel.swift @@ -1,15 +1,15 @@ -import UIKit import SnapKit +import UIKit class DiffLabel: UILabel { - override init(frame: CGRect) { super.init(frame: frame) setContentCompressionResistancePriority(.required, for: .horizontal) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -26,13 +26,11 @@ class DiffLabel: UILabel { func clear() { text = nil } - } extension DiffLabel { - static func formatted(value: Decimal?) -> String? { - guard let value = value else { + guard let value else { return "----" } @@ -40,7 +38,7 @@ extension DiffLabel { } static func color(value: Decimal?, highlight: Bool = true) -> UIColor { - guard let value = value else { + guard let value else { return .themeGray50 } @@ -50,5 +48,4 @@ extension DiffLabel { return value.isSignMinus ? .themeLucian : .themeRemus } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormAmountInputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormAmountInputView.swift index 27eb9c4c85..fc1577778e 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormAmountInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormAmountInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import RxSwift +import SnapKit +import ThemeKit +import UIKit class FormAmountInputView: UIView { private let viewModel: AmountInputViewModel @@ -38,7 +38,8 @@ class FormAmountInputView: UIView { subscribe(disposeBag, viewModel.secondaryTextTypeDriver) { [weak self] in self?.amountInputView.secondaryButtonTextColor = self?.textColor(inputType: $0) } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -47,7 +48,7 @@ class FormAmountInputView: UIView { } private func set(amount: String?) { - guard amountInputView.inputText != amount && !viewModel.equalValue(lhs: amountInputView.inputText, rhs: amount) else { //avoid issue with point ("1" and "1.") + guard amountInputView.inputText != amount, !viewModel.equalValue(lhs: amountInputView.inputText, rhs: amount) else { // avoid issue with point ("1" and "1.") return } @@ -72,11 +73,9 @@ class FormAmountInputView: UIView { private func set(secondaryText: String?) { amountInputView.secondaryButtonText = secondaryText ?? "n/a".localized } - } extension FormAmountInputView { - var viewHeight: CGFloat { amountInputView.viewHeight } @@ -95,12 +94,10 @@ extension FormAmountInputView { get { amountInputView.clearHidden } set { amountInputView.clearHidden = newValue } } - } extension FormAmountInputView: IHeightControlView { - - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { amountInputView.onChangeHeight } set { amountInputView.onChangeHeight = newValue } } @@ -108,5 +105,4 @@ extension FormAmountInputView: IHeightControlView { func height(containerWidth: CGFloat) -> CGFloat { amountInputView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormCautionView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormCautionView.swift index 40905dc9ec..daf76362e6 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormCautionView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormCautionView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class FormCautionView: UIView { private let padding = UIEdgeInsets(top: .margin8, left: .margin32, bottom: 0, right: .margin32) @@ -8,7 +8,7 @@ class FormCautionView: UIView { private let label = UILabel() - var onChangeHeight: (() -> ())? + var onChangeHeight: (() -> Void)? init() { super.init(frame: .zero) @@ -22,16 +22,15 @@ class FormCautionView: UIView { label.font = font } - required init(coder: NSCoder) { + @available(*, unavailable) + required init(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension FormCautionView { - func set(caution: Caution?) { - if let caution = caution { + if let caution { label.text = caution.text label.textColor = caution.type.labelColor } else { @@ -51,5 +50,4 @@ extension FormCautionView { return textHeight + padding.height } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormTextView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormTextView.swift index f3af23aee3..b4205189aa 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormTextView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormTextView.swift @@ -1,11 +1,11 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit protocol IFormTextView: UIView { - var onChangeHeight: (() -> ())? { get set } - var onChangeText: ((String?) -> ())? { get set } - var onChangeEditing: ((Bool) -> ())? { get set } + var onChangeHeight: (() -> Void)? { get set } + var onChangeText: ((String?) -> Void)? { get set } + var onChangeEditing: ((Bool) -> Void)? { get set } var isValidText: ((String) -> Bool)? { get set } func becomeFirstResponder() -> Bool @@ -30,9 +30,9 @@ class FormTextView: UIView, IFormTextView { private let textView = UITextView() private let placeholderLabel = UILabel() - var onChangeHeight: (() -> ())? - var onChangeText: ((String?) -> ())? - var onChangeEditing: ((Bool) -> ())? + var onChangeHeight: (() -> Void)? + var onChangeText: ((String?) -> Void)? + var onChangeEditing: ((Bool) -> Void)? var isValidText: ((String) -> Bool)? init() { @@ -61,7 +61,8 @@ class FormTextView: UIView, IFormTextView { placeholderLabel.textColor = .themeGray50 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -97,11 +98,9 @@ class FormTextView: UIView, IFormTextView { private func syncPlaceholder() { placeholderLabel.isHidden = !textView.text.isEmpty } - } extension FormTextView { - var text: String? { get { textView.text @@ -172,11 +171,9 @@ extension FormTextView { } } } - } extension FormTextView: UITextViewDelegate { - public func textViewDidChange(_ textView: UITextView) { onChangeText?(textView.text) syncPlaceholder() @@ -186,7 +183,7 @@ extension FormTextView: UITextViewDelegate { public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { let newText = (textView.text as NSString).replacingCharacters(in: range, with: text) - if text.isEmpty || newText.isEmpty { // allow backspacing in inputView + if text.isEmpty || newText.isEmpty { // allow backspacing in inputView return true } @@ -199,20 +196,17 @@ extension FormTextView: UITextViewDelegate { return isValid } - public func textViewDidBeginEditing(_ textView: UITextView) { + public func textViewDidBeginEditing(_: UITextView) { onChangeEditing?(true) } - public func textViewDidEndEditing(_ textView: UITextView) { + public func textViewDidEndEditing(_: UITextView) { onChangeEditing?(false) } - } extension FormTextView { - func height(containerWidth: CGFloat) -> CGFloat { height(text: textView.text, width: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormValidatedView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormValidatedView.swift index a44b9e6a1d..43e3af6a8a 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormValidatedView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/FormValidatedView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class FormValidatedView: UIView { private let wrapperView = UIView() @@ -30,18 +30,17 @@ class FormValidatedView: UIView { } } - required init(coder: NSCoder) { + @available(*, unavailable) + required init(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension FormValidatedView { - func set(cautionType: CautionType?) { let borderColor: UIColor - if let cautionType = cautionType { + if let cautionType { borderColor = cautionType.borderColor } else { borderColor = .themeSteel20 @@ -50,7 +49,7 @@ extension FormValidatedView { wrapperView.layer.borderColor = borderColor.cgColor } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { contentView.onChangeHeight } set { contentView.onChangeHeight = newValue } } @@ -61,10 +60,9 @@ extension FormValidatedView { return contentViewHeight + padding.height } - } protocol IHeightControlView: UIView { - var onChangeHeight: (() -> ())? { get set } + var onChangeHeight: (() -> Void)? { get set } func height(containerWidth: CGFloat) -> CGFloat } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/HeaderAmountView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/HeaderAmountView.swift index 866c1e9190..fd8f458dc6 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/HeaderAmountView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/HeaderAmountView.swift @@ -1,7 +1,7 @@ -import UIKit +import ComponentKit import SnapKit import ThemeKit -import ComponentKit +import UIKit class HeaderAmountView: UIView { static let height: CGFloat = 131 @@ -34,16 +34,17 @@ class HeaderAmountView: UIView { convertedAmountButton.font = .body } - required init(coder: NSCoder) { + @available(*, unavailable) + required init(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - var onTapAmount: (() -> ())? { + var onTapAmount: (() -> Void)? { get { amountButton.onTap } set { amountButton.onTap = newValue } } - var onTapConvertedAmount: (() -> ())? { + var onTapConvertedAmount: (() -> Void)? { get { convertedAmountButton.onTap } set { convertedAmountButton.onTap = newValue } } @@ -57,5 +58,4 @@ class HeaderAmountView: UIView { convertedAmountButton.text = convertedAmountText convertedAmountButton.textColor = expired ? .themeGray50 : .themeGray } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputBadgeWrapperView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputBadgeWrapperView.swift index 406cb96dd3..0b606cfefa 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputBadgeWrapperView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputBadgeWrapperView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class InputBadgeWrapperView: UIView, ISizeAwareView { let badgeView = BadgeView() @@ -20,7 +20,8 @@ class InputBadgeWrapperView: UIView, ISizeAwareView { badgeView.setContentHuggingPriority(.defaultHigh, for: .horizontal) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -31,5 +32,4 @@ class InputBadgeWrapperView: UIView, ISizeAwareView { return text.size(containerWidth: containerWidth, font: badgeView.font).width } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputPrefixWrapperView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputPrefixWrapperView.swift index ce0dffde90..36e0b81e14 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputPrefixWrapperView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputPrefixWrapperView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class InputPrefixWrapperView: UIView, ISizeAwareView { let label = UILabel() @@ -19,7 +19,8 @@ class InputPrefixWrapperView: UIView, ISizeAwareView { label.setContentHuggingPriority(.defaultHigh, for: .horizontal) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -30,14 +31,11 @@ class InputPrefixWrapperView: UIView, ISizeAwareView { return text.size(containerWidth: containerWidth, font: label.font).width } - } extension InputPrefixWrapperView { - var textColor: UIColor? { get { label.textColor } set { label.textColor = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryButtonWrapperView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryButtonWrapperView.swift index 92c644683d..7e707751b0 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryButtonWrapperView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryButtonWrapperView.swift @@ -1,13 +1,13 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class InputSecondaryButtonWrapperView: UIView, ISizeAwareView { private let style: SecondaryButton.Style let button = SecondaryButton() - var onTapButton: (() -> ())? + var onTapButton: (() -> Void)? init(style: SecondaryButton.Style) { self.style = style @@ -25,7 +25,8 @@ class InputSecondaryButtonWrapperView: UIView, ISizeAwareView { button.addTarget(self, action: #selector(onTap), for: .touchUpInside) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -33,8 +34,7 @@ class InputSecondaryButtonWrapperView: UIView, ISizeAwareView { onTapButton?() } - func width(containerWidth: CGFloat) -> CGFloat { + func width(containerWidth _: CGFloat) -> CGFloat { SecondaryButton.width(title: button.title(for: .normal) ?? "", style: style, hasImage: false) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryCircleButtonWrapperView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryCircleButtonWrapperView.swift index 73a509bfb2..bba66b7777 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryCircleButtonWrapperView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputSecondaryCircleButtonWrapperView.swift @@ -1,12 +1,12 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class InputSecondaryCircleButtonWrapperView: UIView, ISizeAwareView { let button = SecondaryCircleButton() - var onTapButton: (() -> ())? + var onTapButton: (() -> Void)? init() { super.init(frame: .zero) @@ -21,7 +21,8 @@ class InputSecondaryCircleButtonWrapperView: UIView, ISizeAwareView { button.addTarget(self, action: #selector(onTap), for: .touchUpInside) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -29,8 +30,7 @@ class InputSecondaryCircleButtonWrapperView: UIView, ISizeAwareView { onTapButton?() } - func width(containerWidth: CGFloat) -> CGFloat { + func width(containerWidth _: CGFloat) -> CGFloat { SecondaryCircleButton.size } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStackView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStackView.swift index 20c50b36e0..4cb6ac3848 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStackView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStackView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class InputStackView: UIView { private let stackView = UIStackView() @@ -31,7 +31,8 @@ class InputStackView: UIView { stackView.addArrangedSubview(formTextView) } - required init(coder: NSCoder) { + @available(*, unavailable) + required init(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -43,11 +44,9 @@ class InputStackView: UIView { get { stackView.isUserInteractionEnabled } set { stackView.isUserInteractionEnabled = newValue } } - } extension InputStackView { - var placeholder: String? { get { formTextView.placeholder } set { formTextView.placeholder = newValue } @@ -93,12 +92,12 @@ extension InputStackView { set { formTextView.autocorrectionType = newValue } } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { formTextView.onChangeText } set { formTextView.onChangeText = newValue } } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { formTextView.onChangeEditing } set { formTextView.onChangeEditing = newValue } } @@ -119,27 +118,25 @@ extension InputStackView { leftViews.insert((view, spacing), at: 0) stackView.insertArrangedSubview(view, at: 0) - if let customSpacing = customSpacing { + if let customSpacing { stackView.setCustomSpacing(customSpacing, after: view) } } func appendSubview(_ view: ISizeAwareView, customSpacing: CGFloat? = nil) { let spacing = customSpacing ?? stackView.spacing - + rightViews.append((view, spacing)) stackView.addArrangedSubview(view) - if let customSpacing = customSpacing { + if let customSpacing { stackView.setCustomSpacing(customSpacing, after: view) } } - } extension InputStackView: IHeightControlView { - - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { formTextView.onChangeHeight } set { formTextView.onChangeHeight = newValue } } @@ -153,14 +150,12 @@ extension InputStackView: IHeightControlView { textViewWidth -= view.width(containerWidth: .greatestFiniteMagnitude) + spacing } - for (view, spacing) in visibleRightViews { textViewWidth -= view.width(containerWidth: .greatestFiniteMagnitude) + spacing } return formTextView.height(containerWidth: textViewWidth) } - } protocol ISizeAwareView: UIView { diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStateWrapperView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStateWrapperView.swift index 7170c270b3..1ad114e452 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStateWrapperView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputStateWrapperView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import HUD +import SnapKit +import ThemeKit +import UIKit class InputStateWrapperView: UIView, ISizeAwareView { private let spinner = HUDActivityView.create(with: .small20) @@ -25,7 +25,8 @@ class InputStateWrapperView: UIView, ISizeAwareView { successImageView.tintColor = .themeRemus } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -62,8 +63,7 @@ class InputStateWrapperView: UIView, ISizeAwareView { } } - func width(containerWidth: CGFloat) -> CGFloat { + func width(containerWidth _: CGFloat) -> CGFloat { 20 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputView.swift index 97799b0d84..ea4dc15ec6 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/InputView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class InputView: UIView { private let formValidatedView: FormValidatedView @@ -8,7 +8,7 @@ class InputView: UIView { private let deleteView = InputSecondaryCircleButtonWrapperView() - var onChangeText: ((String?) -> ())? + var onChangeText: ((String?) -> Void)? var isEnabled: Bool = true { didSet { @@ -42,7 +42,8 @@ class InputView: UIView { syncButtonStates() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -67,11 +68,9 @@ class InputView: UIView { deleteView.isHidden = true } } - } extension InputView { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -114,12 +113,12 @@ extension InputView { formValidatedView.set(cautionType: cautionType) } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { inputStackView.onChangeEditing } set { inputStackView.onChangeEditing = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { formValidatedView.onChangeHeight } set { formValidatedView.onChangeHeight = newValue } } @@ -132,5 +131,4 @@ extension InputView { func height(containerWidth: CGFloat) -> CGFloat { formValidatedView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/MultiTextMetricsView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/MultiTextMetricsView.swift index 595d88143f..2a4475d9d2 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/MultiTextMetricsView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/MultiTextMetricsView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class MultiTextMetricsView: UIView { static let titleHeight: CGFloat = MultiTextMetricsView.titleFont.lineHeight @@ -41,7 +41,8 @@ class MultiTextMetricsView: UIView { metricsStackView.axis = .vertical } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -65,11 +66,10 @@ class MultiTextMetricsView: UIView { return } - metricViews.forEach { view in metricsStackView.removeArrangedSubview(view) } metricViews = [] - metricsViewItems.enumerated().forEach { index, item in + metricsViewItems.enumerated().forEach { _, item in let view = MetricsView() bind(view: view, viewItem: item) metricsStackView.addArrangedSubview(view) @@ -86,11 +86,9 @@ class MultiTextMetricsView: UIView { static func viewHeight(viewItems: [MultiTextMetricsView.MetricsViewItem]) -> CGFloat { CGFloat.margin16 + MultiTextMetricsView.titleHeight + CGFloat.margin4 + CGFloat.heightOnePixel + CGFloat.margin8 + CGFloat(viewItems.count) * MetricsView.viewHeight + CGFloat.margin8 } - } extension MultiTextMetricsView { - struct MetricsViewItem { init(value: String?) { self.value = value @@ -112,7 +110,7 @@ extension MultiTextMetricsView { class MetricsView: UIView { static let viewHeight: CGFloat = valueFont.lineHeight + bottomInset - private static let bottomInset: CGFloat = CGFloat.margin8 + private static let bottomInset: CGFloat = .margin8 private static let valueFont: UIFont = .subhead1 private let valueLabel = UILabel() @@ -142,7 +140,8 @@ extension MultiTextMetricsView { valueChangeLabel.font = .caption } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -160,7 +159,5 @@ extension MultiTextMetricsView { get { valueChangeLabel.textColor } set { valueChangeLabel.textColor = newValue } } - } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftAssetView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftAssetView.swift index 2ed072cf1d..62eb4133e1 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftAssetView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftAssetView.swift @@ -1,7 +1,7 @@ -import UIKit +import Kingfisher import SnapKit import ThemeKit -import Kingfisher +import UIKit class NftAssetView: UIView { private static let imageMargin: CGFloat = .margin4 @@ -20,7 +20,7 @@ class NftAssetView: UIView { private let countWrapper = UIView() private let countLabel = UILabel() - var onTap: (() -> ())? + var onTap: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) @@ -141,7 +141,8 @@ class NftAssetView: UIView { fiatPriceLabel.textColor = .themeGray } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -195,14 +196,11 @@ class NftAssetView: UIView { imageView.image = nil } } - } extension NftAssetView { - static func height(containerWidth: CGFloat) -> CGFloat { let imageSize = containerWidth - imageMargin * 2 return imageMargin + imageSize + bottomHeight } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftImageView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftImageView.swift index 1efb0bee9a..6aa19ee707 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftImageView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/NftImageView.swift @@ -1,7 +1,7 @@ -import UIKit +import Kingfisher import SnapKit import ThemeKit -import Kingfisher +import UIKit import WebKit class NftImageView: UIView { @@ -30,16 +30,17 @@ class NftImageView: UIView { webView.isUserInteractionEnabled = false } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func set(nftImage: NftImage) { switch nftImage { - case .image(let image): + case let .image(image): imageView.image = image webView.alpha = 0 - case .svg(let string): + case let .svg(string): imageView.image = nil webView.alpha = 0 webView.loadHTMLString(html(svgString: string), baseURL: nil) @@ -50,11 +51,9 @@ class NftImageView: UIView { var currentImage: UIImage? { imageView.image } - } extension NftImageView { - func html(svgString: String) -> String { """ @@ -83,5 +82,4 @@ extension NftImageView { """ } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasswordInputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasswordInputView.swift index 5ec8e2957f..5081f09717 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasswordInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasswordInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class PasswordInputView: UIView { private let formValidatedView: FormValidatedView @@ -10,7 +10,7 @@ class PasswordInputView: UIView { private let secureButtonView = TransparentIconButtonView() private let insecureButtonView = TransparentIconButtonView() - var onTextSecurityChange: ((Bool) -> ())? + var onTextSecurityChange: ((Bool) -> Void)? init() { formValidatedView = FormValidatedView(contentView: inputStackView, padding: UIEdgeInsets(top: 0, left: .margin16, bottom: 0, right: .margin16)) @@ -38,14 +38,13 @@ class PasswordInputView: UIView { inputStackView.appendSubview(insecureButtonView) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension PasswordInputView { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -56,7 +55,7 @@ extension PasswordInputView { set { inputStackView.text = newValue } } - var onChangeText: ((String?) -> ())? { + var onChangeText: ((String?) -> Void)? { get { inputStackView.onChangeText } set { inputStackView.onChangeText = newValue } } @@ -79,5 +78,4 @@ extension PasswordInputView { func height(containerWidth: CGFloat) -> CGFloat { formValidatedView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasteInputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasteInputView.swift index ba01a84eb6..51d69d0dc5 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasteInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/PasteInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class PasteInputView: UIView { private let formValidatedView: FormValidatedView @@ -24,8 +24,8 @@ class PasteInputView: UIView { } } - var onChangeText: ((String?) -> ())? - var onFetchText: ((String?) -> ())? + var onChangeText: ((String?) -> Void)? + var onFetchText: ((String?) -> Void)? init() { formValidatedView = FormValidatedView(contentView: inputStackView, padding: UIEdgeInsets(top: 0, left: .margin16, bottom: 0, right: .margin16)) @@ -59,7 +59,8 @@ class PasteInputView: UIView { syncButtonStates() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -90,11 +91,9 @@ class PasteInputView: UIView { pasteView.isHidden = false } } - } extension PasteInputView { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -122,12 +121,12 @@ extension PasteInputView { formValidatedView.set(cautionType: cautionType) } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { inputStackView.onChangeEditing } set { inputStackView.onChangeEditing = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { formValidatedView.onChangeHeight } set { formValidatedView.onChangeHeight = newValue } } @@ -135,5 +134,4 @@ extension PasteInputView { func height(containerWidth: CGFloat) -> CGFloat { formValidatedView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/BasePerformanceCollectionViewCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/BasePerformanceCollectionViewCell.swift index e02b663a9b..8e69a0076d 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/BasePerformanceCollectionViewCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/BasePerformanceCollectionViewCell.swift @@ -27,7 +27,8 @@ class BasePerformanceCollectionViewCell: UICollectionViewCell { leftSeparator.backgroundColor = .themeSteel10 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -35,5 +36,4 @@ class BasePerformanceCollectionViewCell: UICollectionViewCell { leftSeparator.isHidden = horizontalFirst topSeparator.isHidden = verticalFirst } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceContentCollectionViewCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceContentCollectionViewCell.swift index b0180984e8..92d9164c02 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceContentCollectionViewCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceContentCollectionViewCell.swift @@ -1,7 +1,6 @@ import UIKit class PerformanceContentCollectionViewCell: BasePerformanceCollectionViewCell { - private let label = DiffLabel() override init(frame: CGRect) { @@ -15,7 +14,8 @@ class PerformanceContentCollectionViewCell: BasePerformanceCollectionViewCell { label.font = .caption } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -24,5 +24,4 @@ class PerformanceContentCollectionViewCell: BasePerformanceCollectionViewCell { label.set(value: value) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceSideCollectionViewCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceSideCollectionViewCell.swift index 4b5e01ed45..8523a01fb2 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceSideCollectionViewCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceSideCollectionViewCell.swift @@ -1,7 +1,6 @@ import UIKit class PerformanceSideCollectionViewCell: BasePerformanceCollectionViewCell { - private let label = UILabel() override init(frame: CGRect) { @@ -13,7 +12,8 @@ class PerformanceSideCollectionViewCell: BasePerformanceCollectionViewCell { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -46,5 +46,4 @@ class PerformanceSideCollectionViewCell: BasePerformanceCollectionViewCell { get { label.text } set { label.text = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceTableViewCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceTableViewCell.swift index 0bf1f1de97..fcebb54d07 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceTableViewCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/Performance/PerformanceTableViewCell.swift @@ -1,9 +1,9 @@ -import UIKit +import ComponentKit +import RxCocoa +import RxSwift import SnapKit import ThemeKit -import RxSwift -import RxCocoa -import ComponentKit +import UIKit class PerformanceTableViewCell: BaseThemeCell { private let disposeBag = DisposeBag() @@ -41,7 +41,8 @@ class PerformanceTableViewCell: BaseThemeCell { collectionView.registerCell(forClass: PerformanceContentCollectionViewCell.self) } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -49,16 +50,14 @@ class PerformanceTableViewCell: BaseThemeCell { self.viewItems = viewItems collectionView.reloadData() } - } extension PerformanceTableViewCell: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { - - public func numberOfSections(in collectionView: UICollectionView) -> Int { + public func numberOfSections(in _: UICollectionView) -> Int { viewItems.count } - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + func collectionView(_: UICollectionView, numberOfItemsInSection section: Int) -> Int { viewItems[section].count } @@ -69,24 +68,24 @@ extension PerformanceTableViewCell: UICollectionViewDelegateFlowLayout, UICollec } } - func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { let verticalFirst = indexPath.section == 0 let horizontalFirst = indexPath.item == 0 let viewItem = viewItems[indexPath.section][indexPath.item] switch viewItem { - case .title(let title), .subtitle(let title), .content(let title): bindSideCell(title: title, type: viewItem, cell: cell, horizontalFirst: horizontalFirst, verticalFirst: verticalFirst) - case .value(let amount): bindContentCell(amount: amount, cell: cell, horizontalFirst: horizontalFirst, verticalFirst: verticalFirst) + case let .title(title), let .subtitle(title), let .content(title): bindSideCell(title: title, type: viewItem, cell: cell, horizontalFirst: horizontalFirst, verticalFirst: verticalFirst) + case let .value(amount): bindContentCell(amount: amount, cell: cell, horizontalFirst: horizontalFirst, verticalFirst: verticalFirst) } } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let minWidth = collectionView.frame.size.width / 4 let currentWidth = collectionView.frame.size.width / CGFloat(viewItems[indexPath.section].count) return CGSize(width: max(minWidth, currentWidth), height: Self.gridRowHeight) } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { 0 } @@ -102,13 +101,10 @@ extension PerformanceTableViewCell: UICollectionViewDelegateFlowLayout, UICollec cell.set(value: amount, horizontalFirst: horizontalFirst, verticalFirst: verticalFirst) } } - } extension PerformanceTableViewCell { - static func height(viewItems: [[CoinOverviewViewModel.PerformanceViewItem]]) -> CGFloat { CGFloat(viewItems.count) * gridRowHeight } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/ResendPasteInputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/ResendPasteInputView.swift index fda5a5f711..1d16219a90 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/ResendPasteInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/ResendPasteInputView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class ResendPasteInputView: UIView { private let formValidatedView: FormValidatedView @@ -25,9 +25,9 @@ class ResendPasteInputView: UIView { } } - var onChangeText: ((String?) -> ())? - var onFetchText: ((String?) -> ())? - var onResend: (() -> ())? + var onChangeText: ((String?) -> Void)? + var onFetchText: ((String?) -> Void)? + var onResend: (() -> Void)? init() { formValidatedView = FormValidatedView(contentView: inputStackView, padding: UIEdgeInsets(top: 0, left: .margin16, bottom: 0, right: .margin16)) @@ -66,7 +66,8 @@ class ResendPasteInputView: UIView { syncButtonStates() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -103,11 +104,9 @@ class ResendPasteInputView: UIView { pasteView.isHidden = false } } - } extension ResendPasteInputView { - var inputPlaceholder: String? { get { inputStackView.placeholder } set { inputStackView.placeholder = newValue } @@ -135,12 +134,12 @@ extension ResendPasteInputView { formValidatedView.set(cautionType: cautionType) } - var onChangeEditing: ((Bool) -> ())? { + var onChangeEditing: ((Bool) -> Void)? { get { inputStackView.onChangeEditing } set { inputStackView.onChangeEditing = newValue } } - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { formValidatedView.onChangeHeight } set { formValidatedView.onChangeHeight = newValue } } @@ -148,5 +147,4 @@ extension ResendPasteInputView { func height(containerWidth: CGFloat) -> CGFloat { formValidatedView.height(containerWidth: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelectableValueView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelectableValueView.swift index 069f1b52d8..982a50bfde 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelectableValueView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelectableValueView.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import UIExtensions +import UIKit class SelectableValueView: UIView { weak var delegate: ISelectableValueViewDelegate? @@ -71,7 +71,8 @@ class SelectableValueView: UIView { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -85,7 +86,6 @@ class SelectableValueView: UIView { valueLabel.textColor = enabled ? .themeLeah : .themeGray50 dropDownImageView.tintColor = enabled ? .themeGray : .themeGray50 } - } protocol ISelectableValueViewDelegate: AnyObject { diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelfSizedSectionsTableView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelfSizedSectionsTableView.swift index 8f7669ac7e..e82eb249d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelfSizedSectionsTableView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SelfSizedSectionsTableView.swift @@ -1,8 +1,7 @@ -import UIKit import SectionsTableView +import UIKit class SelfSizedSectionsTableView: SectionsTableView { - override init(style: Style) { super.init(style: style) @@ -13,7 +12,8 @@ class SelfSizedSectionsTableView: SectionsTableView { setContentHuggingPriority(.defaultHigh, for: .vertical) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -32,5 +32,4 @@ class SelfSizedSectionsTableView: SectionsTableView { override var intrinsicContentSize: CGSize { CGSize(width: contentSize.width, height: contentSize.height + adjustedContentInset.bottom) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SingleLineFormTextView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SingleLineFormTextView.swift index e5a2d9853b..e58c5e5035 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SingleLineFormTextView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/SingleLineFormTextView.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class SingleLineFormTextView: UIView, IFormTextView { private var textViewFont: UIFont = .body @@ -9,21 +9,21 @@ class SingleLineFormTextView: UIView, IFormTextView { let textField = UITextField() private let placeholderLabel = UILabel() - var onChangeHeight: (() -> ())? - var onChangeText: ((String?) -> ())? - var onChangeEditing: ((Bool) -> ())? + var onChangeHeight: (() -> Void)? + var onChangeText: ((String?) -> Void)? + var onChangeEditing: ((Bool) -> Void)? var isValidText: ((String) -> Bool)? var textFieldInset: UIEdgeInsets = .zero var prefix: String? { didSet { let text = textField.text ?? "" - if let prefix = prefix { + if let prefix { if !text.hasPrefix(prefix) { textField.text = prefix + (textField.text ?? "") syncPlaceholder() } - } else if let oldValue = oldValue, text.hasPrefix(oldValue) { + } else if let oldValue, text.hasPrefix(oldValue) { textField.text = text.stripping(prefix: oldValue) syncPlaceholder() } @@ -63,7 +63,8 @@ class SingleLineFormTextView: UIView, IFormTextView { placeholderLabel.textColor = .themeGray50 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -71,8 +72,8 @@ class SingleLineFormTextView: UIView, IFormTextView { textField.becomeFirstResponder() } - private func height(text: String, width: CGFloat) -> CGFloat { - round(textViewFont.lineHeight) + textFieldInset.height + private func height(text _: String, width _: CGFloat) -> CGFloat { + round(textViewFont.lineHeight) + textFieldInset.height } private func syncPlaceholder() { @@ -83,11 +84,9 @@ class SingleLineFormTextView: UIView, IFormTextView { onChangeText?(textField.text?.stripping(prefix: prefix)) syncPlaceholder() } - } extension SingleLineFormTextView { - var text: String? { get { textField.text?.stripping(prefix: prefix) @@ -171,13 +170,11 @@ extension SingleLineFormTextView { } } } - } extension SingleLineFormTextView: UITextFieldDelegate { - public func textFieldDidChangeSelection(_ textField: UITextField) { - if let prefix = prefix, let selectedTextRange = textField.selectedTextRange { + if let prefix, let selectedTextRange = textField.selectedTextRange { let selectedRange = textField.range(textRange: selectedTextRange) if selectedRange.location < prefix.count { let length = max(0, selectedRange.length - prefix.count) @@ -191,13 +188,13 @@ extension SingleLineFormTextView: UITextFieldDelegate { public func textField(_ textView: UITextField, shouldChangeCharactersIn range: NSRange, replacementString text: String) -> Bool { let newText = ((textView.text ?? "") as NSString).replacingCharacters(in: range, with: text) - if let prefix = prefix { //avoid delete prefix if it was set + if let prefix { // avoid delete prefix if it was set if !newText.hasPrefix(prefix) { return false } } - if text.isEmpty || newText.isEmpty { // allow backspacing in inputView + if text.isEmpty || newText.isEmpty { // allow backspacing in inputView return true } @@ -210,20 +207,17 @@ extension SingleLineFormTextView: UITextFieldDelegate { return isValid } - public func textFieldDidBeginEditing(_ textField: UITextField) { + public func textFieldDidBeginEditing(_: UITextField) { onChangeEditing?(true) } - public func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) { + public func textFieldDidEndEditing(_: UITextField, reason _: UITextField.DidEndEditingReason) { onChangeEditing?(false) } - } extension SingleLineFormTextView { - func height(containerWidth: CGFloat) -> CGFloat { height(text: textField.text ?? "", width: containerWidth) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputCell.swift index df901a1002..36c832d164 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputCell.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class StepperAmountInputCell: UITableViewCell { private let formValidatedView: FormValidatedView @@ -21,18 +21,17 @@ class StepperAmountInputCell: UITableViewCell { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } override func becomeFirstResponder() -> Bool { amountInputView.becomeFirstResponder() } - } extension StepperAmountInputCell { - var cellHeight: CGFloat { amountInputView.viewHeight } @@ -42,7 +41,7 @@ extension StepperAmountInputCell { set { amountInputView.value = newValue } } - var onChangeValue: ((Decimal) -> ())? { + var onChangeValue: ((Decimal) -> Void)? { get { amountInputView.onChangeValue } set { amountInputView.onChangeValue = newValue } } @@ -50,5 +49,4 @@ extension StepperAmountInputCell { func set(cautionType: CautionType?) { formValidatedView.set(cautionType: cautionType) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputView.swift index bdb543e2f0..00764799b7 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/StepperAmountInput/StepperAmountInputView.swift @@ -1,10 +1,10 @@ -import Foundation -import UIKit -import ThemeKit -import SnapKit import ComponentKit -import RxSwift +import Foundation import RxCocoa +import RxSwift +import SnapKit +import ThemeKit +import UIKit class StepperAmountInputView: UIView { let disposeBag = DisposeBag() @@ -29,7 +29,7 @@ class StepperAmountInputView: UIView { private let minusView = InputSecondaryCircleButtonWrapperView() private let plusView = InputSecondaryCircleButtonWrapperView() - var onChangeValue: ((Decimal) -> ())? + var onChangeValue: ((Decimal) -> Void)? init(allowFractionalNumbers: Bool) { fractionalsAllowed = allowFractionalNumbers @@ -65,7 +65,8 @@ class StepperAmountInputView: UIView { } } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -96,8 +97,9 @@ class StepperAmountInputView: UIView { } private func decimalValue(of text: String?) -> Decimal { - guard let text = text, !text.isEmpty, - let decimal = Decimal(string: text, locale: .current) else { + guard let text, !text.isEmpty, + let decimal = Decimal(string: text, locale: .current) + else { return 0 } @@ -123,11 +125,9 @@ class StepperAmountInputView: UIView { set(valueOf: textValue(currentValue + 1)) emitValueIfChanged() } - } extension StepperAmountInputView { - var value: Decimal? { get { currentValue @@ -163,21 +163,17 @@ extension StepperAmountInputView { inputStackView.textColor = newValue } } - } extension StepperAmountInputView: IHeightControlView { // required in FormValidatedView, but not used yet - - var onChangeHeight: (() -> ())? { + var onChangeHeight: (() -> Void)? { get { nil } - set { - } + set {} } - func height(containerWidth: CGFloat) -> CGFloat { + func height(containerWidth _: CGFloat) -> CGFloat { 0 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsHeaderView.swift index 53da69aa61..9cf8034433 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsHeaderView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class TextDropDownAndSettingsHeaderView: UITableViewHeaderFooterView { static let height: CGFloat = TextDropDownAndSettingsView.height @@ -25,21 +25,22 @@ class TextDropDownAndSettingsHeaderView: UITableViewHeaderFooterView { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - var onTapDropDown: (() -> ())? { + var onTapDropDown: (() -> Void)? { get { view.onTapDropDown } set { view.onTapDropDown = newValue } } - var onTapSettings: (() -> ())? { + var onTapSettings: (() -> Void)? { get { view.onTapSettings } set { view.onTapSettings = newValue } } - var onTapSelector: ((Int) -> ())? { + var onTapSelector: ((Int) -> Void)? { get { view.onTapSelector } set { view.onTapSelector = newValue } } @@ -60,5 +61,4 @@ class TextDropDownAndSettingsHeaderView: UITableViewHeaderFooterView { func setSelector(isEnabled: Bool) { view.setSelector(isEnabled: isEnabled) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsView.swift index 2e85778b05..f74c0f5b11 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextDropDownAndSettingsView.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class TextDropDownAndSettingsView: UIView { static let height: CGFloat = .heightSingleLineCell @@ -12,9 +12,9 @@ class TextDropDownAndSettingsView: UIView { private let selectorButton = SelectorButton() private let settingsButton = SecondaryCircleButton() - var onTapDropDown: (() -> ())? - var onTapSettings: (() -> ())? - var onTapSelector: ((Int) -> ())? + var onTapDropDown: (() -> Void)? + var onTapSettings: (() -> Void)? + var onTapSelector: ((Int) -> Void)? init() { super.init(frame: .zero) @@ -47,7 +47,8 @@ class TextDropDownAndSettingsView: UIView { settingsButton.addTarget(self, action: #selector(onTapSettingsButton), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -83,5 +84,4 @@ class TextDropDownAndSettingsView: UIView { func setSelector(isEnabled: Bool) { selectorButton.isEnabled = isEnabled } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextFieldStackView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextFieldStackView.swift index abdfd9c480..d14bb2a19c 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextFieldStackView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TextFieldStackView.swift @@ -1,13 +1,13 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class TextFieldStackView: UIView { private let stackView = UIStackView() private let textField = UITextField() - var onChangeText: ((String?) -> ())? - var onReturn: (() -> ())? + var onChangeText: ((String?) -> Void)? + var onReturn: (() -> Void)? var onSpaceKey: (() -> Bool)? var isValidText: ((String?) -> Bool)? @@ -36,7 +36,8 @@ class TextFieldStackView: UIView { stackView.addArrangedSubview(textField) } - required init(coder: NSCoder) { + @available(*, unavailable) + required init(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -47,17 +48,15 @@ class TextFieldStackView: UIView { @objc private func textFieldDidChange() { onChangeText?(textField.text) } - } extension TextFieldStackView: UITextFieldDelegate { - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { + func textFieldShouldReturn(_: UITextField) -> Bool { onReturn?() return true } - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + func textField(_: UITextField, shouldChangeCharactersIn _: NSRange, replacementString string: String) -> Bool { let isValid = isValidText?(string) ?? true if !isValid { @@ -66,11 +65,9 @@ extension TextFieldStackView: UITextFieldDelegate { return isValid } - } extension TextFieldStackView { - var placeholder: String? { get { textField.placeholder } set { textField.placeholder = newValue } @@ -104,7 +101,7 @@ extension TextFieldStackView { func prependSubview(_ view: UIView, customSpacing: CGFloat? = nil) { stackView.insertArrangedSubview(view, at: 0) - if let customSpacing = customSpacing { + if let customSpacing { stackView.setCustomSpacing(customSpacing, after: view) } } @@ -112,5 +109,4 @@ extension TextFieldStackView { func appendSubview(_ view: UIView) { stackView.addArrangedSubview(view) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TransparentIconButtonView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TransparentIconButtonView.swift index 3c6b5050fc..9249f18f2b 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TransparentIconButtonView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Components/TransparentIconButtonView.swift @@ -1,10 +1,10 @@ -import UIKit import SnapKit +import UIKit public class TransparentIconButtonView: UIView, ISizeAwareView { public let button = UIButton() - public var onTap: (() -> ())? + public var onTap: (() -> Void)? override public init(frame: CGRect) { super.init(frame: frame) @@ -20,7 +20,8 @@ public class TransparentIconButtonView: UIView, ISizeAwareView { button.addTarget(self, action: #selector(_onTap), for: .touchUpInside) } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -32,8 +33,7 @@ public class TransparentIconButtonView: UIView, ISizeAwareView { button.setImage(image?.withTintColor(.themeGray), for: .normal) } - func width(containerWidth: CGFloat) -> CGFloat { + func width(containerWidth _: CGFloat) -> CGFloat { 20 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardAwareViewController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardAwareViewController.swift index 4c4c985ffe..b9c8c123fb 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardAwareViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardAwareViewController.swift @@ -1,8 +1,8 @@ -import ThemeKit -import UIKit -import RxSwift import RxCocoa +import RxSwift +import ThemeKit import UIExtensions +import UIKit class KeyboardAwareViewController: ThemeViewController { private let scrollViews: [UIScrollView] @@ -16,13 +16,14 @@ class KeyboardAwareViewController: ThemeViewController { updateInsets() } } + var additionalInsetsOnlyForClosedKeyboard: Bool = true // AdditionalContentInsets by default using only in closed state (mean that not for accessoryView, but wrapper on screen bottom) var oldPadding: CGFloat = 0 var accessoryView: UIView? - var ignoreSafeAreaForAccessoryView = true // when accessory view is wrapper which covering safeArea. You must setInitialState(bottomPadding: wrapper.height) in didAppear(:) + var ignoreSafeAreaForAccessoryView = true // when accessory view is wrapper which covering safeArea. You must setInitialState(bottomPadding: wrapper.height) in didAppear(:) private var pseudoAccessoryView: PseudoAccessoryView? @@ -33,7 +34,7 @@ class KeyboardAwareViewController: ThemeViewController { var showAccessoryView: Bool = true open var accessoryViewHeight: CGFloat { - showAccessoryView ? floor(accessoryView?.height ?? 0) : 0 // need to use height without safe-area because tableview already use safe-area insets + showAccessoryView ? floor(accessoryView?.height ?? 0) : 0 // need to use height without safe-area because tableview already use safe-area insets } override open var inputAccessoryView: UIView? { @@ -61,7 +62,8 @@ class KeyboardAwareViewController: ThemeViewController { } } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -143,7 +145,8 @@ class KeyboardAwareViewController: ThemeViewController { @objc private func keyboardWillShow(notification: Notification) { guard let oldKeyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue, let keyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue, - oldKeyboardFrame != keyboardFrame else { + oldKeyboardFrame != keyboardFrame + else { return } // check in visible only accessoryView. If true - keyboard is hidden @@ -163,7 +166,7 @@ class KeyboardAwareViewController: ThemeViewController { } } - @objc private func keyboardWillHide(notification: Notification) { + @objc private func keyboardWillHide(notification _: Notification) { // try to enable dismiss controller by swipe when keyboard is hidden navigationController?.presentationController?.presentedView?.gestureRecognizers?.first?.isEnabled = true keyboardFrame = nil @@ -192,7 +195,7 @@ class KeyboardAwareViewController: ThemeViewController { } } - public func updateUIKeyboard(initial: Bool = false) { + public func updateUIKeyboard(initial _: Bool = false) { UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() @@ -223,7 +226,7 @@ class KeyboardAwareViewController: ThemeViewController { } override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) { - let stopObserveKeyboard = !viewControllerToPresent.isKind(of: UISearchController.self) // SearchControllers presenting transparent on parent and need to obsevre parent content + let stopObserveKeyboard = !viewControllerToPresent.isKind(of: UISearchController.self) // SearchControllers presenting transparent on parent and need to obsevre parent content if stopObserveKeyboard { view.endEditing(true) } @@ -236,7 +239,7 @@ class KeyboardAwareViewController: ThemeViewController { viewControllerToPresent.presentationController?.delegate = self let awaitClosingKeyboardTime: TimeInterval = keyboardFrame == nil ? 0 : 0.05 - DispatchQueue.main.asyncAfter(deadline: .now() + awaitClosingKeyboardTime) { // Time delay needed to handle keyboard dismissing (change insets and accessory position) + DispatchQueue.main.asyncAfter(deadline: .now() + awaitClosingKeyboardTime) { // Time delay needed to handle keyboard dismissing (change insets and accessory position) super.present(viewControllerToPresent, animated: flag) { [weak self] in if stopObserveKeyboard { self?.observeKeyboard(false) @@ -247,7 +250,7 @@ class KeyboardAwareViewController: ThemeViewController { } func syncContentOffsetIfRequired(textView: UITextView) { - guard let keyboardFrame = keyboardFrame else { + guard let keyboardFrame else { return } @@ -266,8 +269,8 @@ class KeyboardAwareViewController: ThemeViewController { scrollViews[0].setContentOffset(CGPoint(x: 0, y: shift), animated: true) } - } + extension KeyboardAwareViewController { public var keyboardVisibilityDriver: Driver { keyboardVisibilityRelay.asDriver() @@ -275,8 +278,7 @@ extension KeyboardAwareViewController { } extension KeyboardAwareViewController: PseudoAccessoryViewDelegate { - - func pseudoAccessoryView(_ pseudoAccessoryView: PseudoAccessoryView, keyboardFrameDidChange frame: CGRect) { + func pseudoAccessoryView(_: PseudoAccessoryView, keyboardFrameDidChange frame: CGRect) { let keyboardFrame = view.convert(frame, from: nil) if shouldObserveKeyboard { @@ -285,30 +287,25 @@ extension KeyboardAwareViewController: PseudoAccessoryViewDelegate { pendingFrame = keyboardFrame } } - } extension KeyboardAwareViewController: UIAdaptivePresentationControllerDelegate { - - public func presentationControllerWillDismiss(_ presentationController: UIPresentationController) { + public func presentationControllerWillDismiss(_: UIPresentationController) { // print("presentationControllerWillDismiss : \(presentationController)") } - public func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + public func presentationControllerDidDismiss(_: UIPresentationController) { observeKeyboard(true) // print("presentationControllerDidDismiss : \(presentationController)") } - public func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) { + public func presentationControllerDidAttemptToDismiss(_: UIPresentationController) { // print("presentationControllerDidDismiss : \(presentationController)") } - } extension KeyboardAwareViewController: UIGestureRecognizerDelegate { - - func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { + func gestureRecognizer(_: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { touch.view is UITableView } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardObservingViewController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardObservingViewController.swift index baf17fe13c..7d5db39c12 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardObservingViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/KeyboardObservingViewController.swift @@ -1,11 +1,10 @@ -import UIKit -import UIExtensions import HUD -import RxSwift import RxCocoa +import RxSwift +import UIExtensions +import UIKit class KeyboardObservingViewController: UIViewController { - let disposeBag = DisposeBag() var keyboardFrameDisposable: Disposable? @@ -45,10 +44,9 @@ class KeyboardObservingViewController: UIViewController { } } - func enableContent(enabled: Bool) { - } + func enableContent(enabled _: Bool) {} -//Handle keyboard auto open/close + // Handle keyboard auto open/close func onKeyboardFrameChange(_ notification: Notification) { let screenKeyboardFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue @@ -61,7 +59,5 @@ class KeyboardObservingViewController: UIViewController { updateUI(keyboardHeight: keyboardHeight, duration: duration, options: UIView.AnimationOptions(rawValue: curve << 16)) } - func updateUI(keyboardHeight: CGFloat, duration: TimeInterval = 0.2, options: UIView.AnimationOptions = .curveLinear, completion: (() -> ())? = nil) { - } - + func updateUI(keyboardHeight _: CGFloat, duration _: TimeInterval = 0.2, options _: UIView.AnimationOptions = .curveLinear, completion _: (() -> Void)? = nil) {} } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeActionSheetController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeActionSheetController.swift index cb812ce7d6..dc3b05e323 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeActionSheetController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeActionSheetController.swift @@ -2,13 +2,14 @@ import UIKit class ThemeActionSheetController: UIViewController { public weak var actionSheetView: ActionSheetView? - public var onInteractiveDismiss: (() -> ())? + public var onInteractiveDismiss: (() -> Void)? init() { super.init(nibName: nil, bundle: nil) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -18,7 +19,7 @@ class ThemeActionSheetController: UIViewController { view.backgroundColor = .themeLawrence } - override func dismiss(animated flag: Bool, completion: (() -> ())? = nil) { + override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { actionSheetView?.contentWillDismissed() super.dismiss(animated: flag, completion: completion) } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeSearchViewController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeSearchViewController.swift index 6e0bfd5979..561ce6324c 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeSearchViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controllers/ThemeSearchViewController.swift @@ -1,7 +1,7 @@ import Combine -import UIKit import HsExtensions import ThemeKit +import UIKit class ThemeSearchViewController: KeyboardAwareViewController { private let searchController = UISearchController(searchResultsController: nil) @@ -24,7 +24,7 @@ class ThemeSearchViewController: KeyboardAwareViewController { navigationItem.hidesSearchBarWhenScrolling = false } - override func dismiss(animated flag: Bool, completion: (() -> ())? = nil) { + override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { if searchController.isActive { searchController.dismiss(animated: false) } @@ -44,21 +44,17 @@ class ThemeSearchViewController: KeyboardAwareViewController { } } } - } extension ThemeSearchViewController: UISearchControllerDelegate { - - public func didPresentSearchController(_ searchController: UISearchController) { + public func didPresentSearchController(_: UISearchController) { DispatchQueue.main.async { self.searchController.searchBar.becomeFirstResponder() } } - } extension ThemeSearchViewController: UISearchResultsUpdating { - public func updateSearchResults(for searchController: UISearchController) { var filter = searchController.searchBar.text?.trimmingCharacters(in: .whitespaces) @@ -72,5 +68,4 @@ extension ThemeSearchViewController: UISearchResultsUpdating { self.filter = filter } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BarPageControl.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BarPageControl.swift index 38c089ec17..ed1c62e39b 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BarPageControl.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BarPageControl.swift @@ -1,6 +1,6 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class BarPageControl: UIView { private let barSize = CGSize(width: 20, height: 4) @@ -16,7 +16,7 @@ class BarPageControl: UIView { init(barCount: Int) { super.init(frame: .zero) - for i in 0.. - .timer(.milliseconds(0), period: .milliseconds(animationDelay), scheduler: MainScheduler.instance) - .subscribe(onNext: { [weak self] _ in - let startIndex = self?.filledCount ?? 0 - self?.updateFillColor(fullFillBefore: startIndex + dx) - dx += 1 - dx = startIndex + dx > count ? 0 : dx - }) + .timer(.milliseconds(0), period: .milliseconds(animationDelay), scheduler: MainScheduler.instance) + .subscribe(onNext: { [weak self] _ in + let startIndex = self?.filledCount ?? 0 + self?.updateFillColor(fullFillBefore: startIndex + dx) + dx += 1 + dx = startIndex + dx > count ? 0 : dx + }) animateDisposable?.disposed(by: disposeBag) } @@ -118,5 +119,4 @@ class BarsProgressView: UIView { bar.backgroundColor = index < filledCount ? filledColor : (index < count ? color : inactiveColor) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BottomSheetTitleView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BottomSheetTitleView.swift index 57d8173810..df3176eb5a 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BottomSheetTitleView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/BottomSheetTitleView.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class BottomSheetTitleView: UIView { private let imageView = UIImageView() @@ -65,7 +65,8 @@ class BottomSheetTitleView: UIView { closeButton.addTarget(self, action: #selector(_onTapClose), for: .touchUpInside) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -78,7 +79,7 @@ class BottomSheetTitleView: UIView { maker.height.equalTo(subtitle != nil ? 72 : 60) } - if let image = image { + if let image { imageView.isHidden = false imageView.snp.updateConstraints { maker in @@ -102,7 +103,7 @@ class BottomSheetTitleView: UIView { titleLabel.font = subtitle != nil ? .body : .headline2 titleLabel.text = title - if let subtitle = subtitle { + if let subtitle { subtitleLabel.isHidden = false subtitleLabel.text = subtitle } else { @@ -111,11 +112,9 @@ class BottomSheetTitleView: UIView { self.viewController = viewController } - } extension BottomSheetTitleView { - enum Image { static let warning: Self = .local(name: "warning_2_24", tint: .warning) static let info: Self = .local(name: "circle_information_24", tint: .gray) @@ -139,4 +138,4 @@ extension BottomSheetTitleView.Image.TintType { case .alert: return .themeLucian } } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/DonutChartView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/DonutChartView.swift index dabf4cc18b..a153cc5609 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/DonutChartView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/DonutChartView.swift @@ -1,9 +1,8 @@ -import UIKit -import ThemeKit import SnapKit +import ThemeKit +import UIKit class DonutChartView: UIView { - var baseColor: UIColor = .themeJacob { didSet { setNeedsDisplay() } } @@ -26,7 +25,8 @@ class DonutChartView: UIView { backgroundColor = .clear } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -35,7 +35,7 @@ class DonutChartView: UIView { return baseColor.withAlphaComponent(1 - CGFloat(index) * diff) } - override func draw(_ rect: CGRect) { + override func draw(_: CGRect) { let radius = bounds.width / 2 let arcWidth = radius * arcWidthPercent @@ -52,11 +52,11 @@ class DonutChartView: UIView { currentPercent = nextPercent let path = UIBezierPath( - arcCenter: center, - radius: radius - arcWidth / 2, - startAngle: startAngle, - endAngle: endAngle, - clockwise: true + arcCenter: center, + radius: radius - arcWidth / 2, + startAngle: startAngle, + endAngle: endAngle, + clockwise: true ) path.lineWidth = arcWidth @@ -64,13 +64,10 @@ class DonutChartView: UIView { path.stroke() } } - } extension DonutChartView { - static func height(containerWidth: CGFloat) -> CGFloat { containerWidth / 2 } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSlider.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSlider.swift index e2d8706a47..c872ef4602 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSlider.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSlider.swift @@ -1,8 +1,8 @@ import UIKit class FeeSlider: UISlider { - var onTracking: ((Float, CGPoint) -> ())? - var finishTracking: ((Float) -> ())? + var onTracking: ((Float, CGPoint) -> Void)? + var finishTracking: ((Float) -> Void)? private var lastValue: Float? @@ -30,11 +30,12 @@ class FeeSlider: UISlider { slideBar.clipsToBounds = true } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - private func correctCenter(touch: UITouch) -> CGPoint { // touch position may be not in center of thumb, we need correct centerX + private func correctCenter(touch: UITouch) -> CGPoint { // touch position may be not in center of thumb, we need correct centerX touch.location(in: nil) } @@ -66,7 +67,7 @@ class FeeSlider: UISlider { lastValue = nil } - override open func endTracking(_ touch: UITouch?, with event: UIEvent?) { + override open func endTracking(_ touch: UITouch?, with event: UIEvent?) { super.endTracking(touch, with: event) finish() } @@ -75,5 +76,4 @@ class FeeSlider: UISlider { super.cancelTracking(with: event) finish() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderValueView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderValueView.swift index a5f5d7ff11..5a539abb8e 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderValueView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderValueView.swift @@ -1,16 +1,17 @@ -import UIKit -import SnapKit import HUD +import SnapKit +import UIKit class FeeSliderValueView: UIView { private let feeRateLabel = UILabel() private let unitNameLabel = UILabel() - public required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - required public init() { + public required init() { super.init(frame: CGRect.zero) backgroundColor = .themeClaude @@ -42,18 +43,15 @@ class FeeSliderValueView: UIView { func set(value: String?) { feeRateLabel.text = value } - } extension FeeSliderValueView: HUDContentViewInterface { - - public func updateConstraints(forSize size: CGSize) { + public func updateConstraints(forSize _: CGSize) { // do nothing } public var actions: [HUDTimeAction] { get { [] } set {} - } // ignore all actions on view - + } // ignore all actions on view } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderWrapper.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderWrapper.swift index 082bb208f1..c463e8302e 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderWrapper.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FeeSliderWrapper.swift @@ -1,6 +1,6 @@ -import UIKit -import HUD import ComponentKit +import HUD +import UIKit class FeeSliderWrapper: UIView { private let slider = FeeSlider() @@ -10,12 +10,12 @@ class FeeSliderWrapper: UIView { private let feeRateView = FeeSliderValueView() private var sliderLastValue: Float? private var step: Int = 1 - var scale: FeePriceScale = FeePriceScale.gwei + var scale: FeePriceScale = .gwei - var finishTracking: ((Float) -> ())? + var finishTracking: ((Float) -> Void)? var sliderRange: ClosedRange { - Int(slider.minimumValue)...Int(slider.maximumValue) + Int(slider.minimumValue) ... Int(slider.maximumValue) } required init?(coder aDecoder: NSCoder) { @@ -58,7 +58,6 @@ class FeeSliderWrapper: UIView { increaseButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) increaseButton.setImage(UIImage(named: "plus_2_20"), for: .normal) increaseButton.addTarget(self, action: #selector(increase), for: .touchUpInside) - } @objc private func decrease() { @@ -135,5 +134,4 @@ class FeeSliderWrapper: UIView { finishTracking?(value) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderCell.swift index 0b461a4a3a..1ea0345826 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderCell.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderCell.swift @@ -1,7 +1,7 @@ -import UIKit -import ThemeKit -import SnapKit import ComponentKit +import SnapKit +import ThemeKit +import UIKit class FilterHeaderCell: UICollectionViewCell { private let button = SecondaryButton() @@ -18,7 +18,8 @@ class FilterHeaderCell: UICollectionViewCell { button.isUserInteractionEnabled = false } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -39,13 +40,10 @@ class FilterHeaderCell: UICollectionViewCell { button.setTitle(title, for: .normal) button.isSelected = selected } - } extension FilterHeaderCell { - static func width(title: String, style: SecondaryButton.Style) -> CGFloat { SecondaryButton.width(title: title, style: style, hasImage: false) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderView.swift index 9a21944151..60c164bc43 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterHeaderView.swift @@ -1,6 +1,6 @@ -import UIKit -import SnapKit import ComponentKit +import SnapKit +import UIKit class FilterHeaderView: UITableViewHeaderFooterView { static var height: CGFloat = FilterView.height @@ -21,7 +21,8 @@ class FilterHeaderView: UITableViewHeaderFooterView { backgroundView?.backgroundColor = .themeNavigationBarBackground } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } @@ -30,7 +31,7 @@ class FilterHeaderView: UITableViewHeaderFooterView { set { view.autoDeselect = newValue } } - var onSelect: ((Int) -> ())? { + var onSelect: ((Int) -> Void)? { get { view.onSelect } set { view.onSelect = newValue } } @@ -46,5 +47,4 @@ class FilterHeaderView: UITableViewHeaderFooterView { func select(index: Int) { view.select(index: index) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterView.swift index b0b51a394b..4e6565ac0a 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/FilterView.swift @@ -1,6 +1,6 @@ -import UIKit -import SnapKit import ComponentKit +import SnapKit +import UIKit class FilterView: UIView { static var height: CGFloat = .heightSingleLineCell @@ -14,13 +14,14 @@ class FilterView: UIView { layoutSelectedView(indexPath: collectionView.indexPathsForSelectedItems?.first ?? IndexPath(item: 0, section: 0)) } } + private var buttonStyle: SecondaryButton.Style private let selectedView = UIView() private let animationDuration: TimeInterval var autoDeselect: Bool = false - var onSelect: ((Int) -> ())? + var onSelect: ((Int) -> Void)? var headerHeight: CGFloat { filters.isEmpty ? 0 : Self.height @@ -81,14 +82,15 @@ class FilterView: UIView { selectedView.backgroundColor = buttonStyle == .tab ? .themeJacob : .clear } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("not implemented") } private func title(index: Int) -> String { switch filters[index] { case .all: return "transactions.filter_all".localized - case .item(let title): return title + case let .item(title): return title } } @@ -112,12 +114,12 @@ class FilterView: UIView { let interitemSpacing = CGFloat(filters.count - 1) * layout.minimumInteritemSpacing let width = collectionView.width - collectionView.contentInset.left - collectionView.contentInset.right - interitemSpacing - var items = Array(0..= width { // elements can't fit into screen - itemWidths = items.map { $0.width } + if initialItemWidth >= width { // elements can't fit into screen + itemWidths = items.map(\.width) return } @@ -126,15 +128,15 @@ class FilterView: UIView { var freeSpace = width - initialItemWidth var sameMinimalWidthItemCount = 1 - while freeSpace != 0 && sameMinimalWidthItemCount < items.count { + while freeSpace != 0, sameMinimalWidthItemCount < items.count { let (newLessWidth, newFreeSpace) = equalize( - count: sameMinimalWidthItemCount, - lessWidth: items[0].width, - greaterWidth: items[sameMinimalWidthItemCount].width, - freeSpace: freeSpace + count: sameMinimalWidthItemCount, + lessWidth: items[0].width, + greaterWidth: items[sameMinimalWidthItemCount].width, + freeSpace: freeSpace ) - for i in 0.. 0 { let delta = freeSpace / CGFloat(items.count) - for i in 0.. Int { + func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { filters.count } @@ -195,23 +196,23 @@ extension FilterView: UICollectionViewDelegateFlowLayout, UICollectionViewDataSo } } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { calculateItemWidths() return CGSize(width: itemWidths[indexPath.item], height: .heightSingleLineCell) } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat { .margin8 } func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { - if let selectedIndexPath = collectionView.indexPathsForSelectedItems?.first, (!autoDeselect && selectedIndexPath == indexPath) { + if let selectedIndexPath = collectionView.indexPathsForSelectedItems?.first, !autoDeselect, selectedIndexPath == indexPath { return false } return true } - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, didSelectItemAt indexPath: IndexPath) { onSelect?(indexPath.item) handleSelected(indexPath: indexPath) @@ -237,7 +238,7 @@ extension FilterView: UICollectionViewDelegateFlowLayout, UICollectionViewDataSo var offset: CGFloat = 0 let spacing = collectionView(collectionView, layout: layout, minimumInteritemSpacingForSectionAt: 0) - for i in 0.. ())? + var onSelect: ((Int) -> Void)? private func imageName(count: Int, index: Int) -> String { "mode_\(count)_\(index + 1)_20" } @@ -16,7 +16,7 @@ class SelectorButton: SecondaryButton { addTarget(self, action: #selector(onTap), for: .touchUpInside) } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } @@ -58,5 +58,4 @@ class SelectorButton: SecondaryButton { public func setSelected(index: Int) { setSelected(index: index, initial: true) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/SimpleSheetTitleView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/SimpleSheetTitleView.swift index cfa33128fc..ca4ec44b4d 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/SimpleSheetTitleView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Controls/SimpleSheetTitleView.swift @@ -1,6 +1,6 @@ -import UIKit import SnapKit import ThemeKit +import UIKit class SimpleSheetTitleView: UIView { static let height: CGFloat = 40 @@ -8,7 +8,7 @@ class SimpleSheetTitleView: UIView { private let textLabel = UILabel() private let separatorView = UIView() - var onTapClose: (() -> ())? + var onTapClose: (() -> Void)? init() { super.init(frame: .zero) @@ -36,7 +36,8 @@ class SimpleSheetTitleView: UIView { separatorView.backgroundColor = .themeSteel10 } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -53,5 +54,4 @@ class SimpleSheetTitleView: UIView { get { textLabel.textColor } set { textLabel.textColor = newValue } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/DateHelper.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/DateHelper.swift index 4aa27bd159..453be89778 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/DateHelper.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/DateHelper.swift @@ -12,7 +12,7 @@ class DateHelper { return DateFormatter.cachedFormatter(format: format).string(from: date) } - func formatTransactionTime(from date: Date, useYesterday: Bool = false) -> String { + func formatTransactionTime(from date: Date, useYesterday _: Bool = false) -> String { DateFormatter.cachedFormatter(format: "\(LanguageHourFormatter.hourFormat):mm").string(from: date) } @@ -84,5 +84,4 @@ class DateHelper { } return DateFormatter.cachedFormatter(format: short ? "MM/dd/yy" : "MMMM d, yyyy") } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Array.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Array.swift index c50829d747..a4617fefc7 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Array.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Array.swift @@ -1,24 +1,21 @@ import Foundation extension Array { - func at(index: Int) -> Element? { - guard self.count > index else { + guard count > index else { return nil } return self[index] } func chunks(_ chunkSize: Int) -> [[Element]] { - stride(from: 0, to: self.count, by: chunkSize).map { - Array(self[$0.. Self { var uniqueElements = [Element]() for element in self { @@ -28,5 +25,4 @@ extension Array where Element: Equatable { } return uniqueElements } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CALayer.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CALayer.swift index 3d67508613..c7e8015bcd 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CALayer.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CALayer.swift @@ -29,7 +29,7 @@ extension CALayer { return animation } - class func perform(withoutAnimation: Bool = true, duration: TimeInterval? = nil, _ action: () -> Void, completion: (() -> ())? = nil) { + class func perform(withoutAnimation: Bool = true, duration: TimeInterval? = nil, _ action: () -> Void, completion: (() -> Void)? = nil) { CATransaction.begin() CATransaction.setAnimationDuration(duration ?? .themeAnimationDuration) CATransaction.setDisableActions(withoutAnimation) @@ -43,5 +43,4 @@ extension CALayer { action() CATransaction.commit() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CellElement.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CellElement.swift index c515785eb4..b16633546c 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CellElement.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/CellElement.swift @@ -1,11 +1,10 @@ -import UIKit import ComponentKit +import UIKit -extension CellBuilderNew.CellElement { // prepared cell elements for most frequency used layouts - +extension CellBuilderNew.CellElement { // prepared cell elements for most frequency used layouts static func textElement(text: Text?, parameters: TextParameters = .none) -> CellBuilderNew.CellElement { .text { component in - if let text = text { + if let text { component.isHidden = false component.font = text.font @@ -37,8 +36,8 @@ extension CellBuilderNew.CellElement { // prepared cell elements for most frequ } static func imageElement(image: Image?, size: ImageSize) -> CellBuilderNew.CellElement { - let block: (ImageComponent) -> () = { component in - if let image = image { + let block: (ImageComponent) -> Void = { component in + if let image { component.isHidden = false if let image = image.image { // setup local image component.imageView.image = image @@ -67,13 +66,13 @@ extension CellBuilderNew.CellElement { // prepared cell elements for most frequ case let accessoryType as ImageAccessoryType: if let image = accessoryType.image { elements.append(.margin8) - elements.append(.image20 { (component: ImageComponent) -> () in + elements.append(.image20 { (component: ImageComponent) in component.imageView.image = image component.isHidden = !accessoryType.visible }) } case let accessoryType as SwitchAccessoryType: - elements.append(.switch { (component: SwitchComponent) -> () in + elements.append(.switch { (component: SwitchComponent) in component.switchView.setOn(accessoryType.isOn, animated: accessoryType.animated) component.onSwitch = accessoryType.onSwitch }) @@ -81,11 +80,9 @@ extension CellBuilderNew.CellElement { // prepared cell elements for most frequ } return elements } - } extension CellBuilderNew.CellElement { - struct Image { static func local(_ image: UIImage?) -> Self { Image(image: image, url: nil, placeholder: nil) } static func url(_ url: String?, placeholder: String? = nil) -> Self { Image(image: nil, url: url, placeholder: placeholder) } @@ -133,7 +130,7 @@ extension CellBuilderNew.CellElement { static let disclosure: AccessoryType = ImageAccessoryType(image: UIImage(named: "arrow_big_forward_20")?.withTintColor(.themeGray)) static let dropdown: AccessoryType = ImageAccessoryType(image: UIImage(named: "arrow_small_down_20")?.withTintColor(.themeGray)) static func check(_ visible: Bool = true) -> AccessoryType { ImageAccessoryType(image: UIImage(named: "check_1_20")?.withTintColor(.themeJacob), visible: visible) } - static func `switch`(isOn: Bool = false, animated: Bool = false, onSwitch: ((Bool) -> ())?) -> AccessoryType { SwitchAccessoryType(isOn: isOn, animated: animated, onSwitch: onSwitch) } + static func `switch`(isOn: Bool = false, animated: Bool = false, onSwitch: ((Bool) -> Void)?) -> AccessoryType { SwitchAccessoryType(isOn: isOn, animated: animated, onSwitch: onSwitch) } } class ImageAccessoryType: AccessoryType { @@ -151,9 +148,9 @@ extension CellBuilderNew.CellElement { class SwitchAccessoryType: AccessoryType { let isOn: Bool let animated: Bool - let onSwitch: ((Bool) -> ())? + let onSwitch: ((Bool) -> Void)? - init(isOn: Bool = false, animated: Bool, onSwitch: ((Bool) -> ())?) { + init(isOn: Bool = false, animated: Bool, onSwitch: ((Bool) -> Void)?) { self.isOn = isOn self.animated = animated self.onSwitch = onSwitch @@ -161,5 +158,4 @@ extension CellBuilderNew.CellElement { super.init() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/ChartConfiguration.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/ChartConfiguration.swift index 2653e83f0a..e563972abc 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/ChartConfiguration.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/ChartConfiguration.swift @@ -1,9 +1,8 @@ -import UIKit import Chart import ThemeKit +import UIKit extension ChartConfiguration { - static var baseChart: ChartConfiguration { ChartConfiguration().applyColors().applyBase() } @@ -77,10 +76,10 @@ extension ChartConfiguration { curveType = .bars curveBottomInset = 18 - trendUpGradient = [.clear] - trendDownGradient = [.clear] - pressedGradient = [.clear] - neutralGradient = [.clear] + trendUpGradient = [.clear] + trendDownGradient = [.clear] + pressedGradient = [.clear] + neutralGradient = [.clear] return self } @@ -99,7 +98,7 @@ extension ChartConfiguration { return self } - @discardableResult private func applyColors(trendIgnore: Bool = false) -> Self { + @discardableResult private func applyColors(trendIgnore _: Bool = false) -> Self { borderColor = .themeSteel20 backgroundColor = .clear @@ -111,7 +110,7 @@ extension ChartConfiguration { trendUpGradient = [UIColor](repeatElement(UIColor(hex: 0x13D670), count: 3)) trendDownGradient = [UIColor(hex: 0x7413D6), UIColor(hex: 0x7413D6), UIColor(hex: 0xFF0303)] pressedGradient = [UIColor](repeatElement(.themeLeah, count: 3)) - neutralGradient = [UIColor](repeatElement(UIColor(hex: 0xFFa800), count: 3)) + neutralGradient = [UIColor](repeatElement(UIColor(hex: 0xFFA800), count: 3)) gradientLocations = [0, 0.05, 1] gradientAlphas = [0, 0, 0.3] @@ -127,18 +126,15 @@ extension ChartConfiguration { return self } - } -extension ChartIndicator.LineConfiguration { - - static public var dominance: Self { +public extension ChartIndicator.LineConfiguration { + static var dominance: Self { Self(color: ChartColor(.themeYellowD.withAlphaComponent(0.5)), width: 1) } - static public var dominanceId: String { + static var dominanceId: String { let indicator = PrecalculatedIndicator(id: MarketGlobalModule.dominance, enabled: true, values: [], configuration: dominance) return indicator.json } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Date.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Date.swift index 143a8ffe1e..5af0bf9060 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Date.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Date.swift @@ -1,30 +1,28 @@ import UIKit -extension Date { - - public func hoursAfterDate(_ aDate: Date) -> Double { +public extension Date { + func hoursAfterDate(_ aDate: Date) -> Double { let ti = timeIntervalSince(aDate) return ti / (60 * 60) } - public func minutesAfterDate(_ aDate: Date) -> Double { + func minutesAfterDate(_ aDate: Date) -> Double { let ti = timeIntervalSince(aDate) return ti / 60 } - public func daysAfterDate(_ aDate: Date) -> Double { + func daysAfterDate(_ aDate: Date) -> Double { let ti = timeIntervalSince(aDate) return ti / (60 * 60 * 24) } - public func isDateInCurrentYear(date: Date) -> Bool { + func isDateInCurrentYear(date: Date) -> Bool { let calendar = Calendar.current let year = calendar.component(.year, from: date) return year == calendar.component(.year, from: Date()) } - func isSameDay(as date: Date) -> Bool { + internal func isSameDay(as date: Date) -> Bool { Calendar.current.compare(self, to: date, toGranularity: .day) == .orderedSame } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Decimal.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Decimal.swift index e4b9492816..b4ac0f06b7 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Decimal.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Decimal.swift @@ -1,10 +1,9 @@ -import Foundation import BigInt +import Foundation -fileprivate let max256ByteNumber = BigUInt(Data(hex: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) +private let max256ByteNumber = BigUInt(Data(hex: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) extension Decimal { - init?(bigUInt: BigUInt, decimals: Int) { guard let significand = Decimal(string: bigUInt.description) else { return nil @@ -26,5 +25,4 @@ extension Decimal { let maxInDecimal = Decimal(sign: .plus, exponent: -decimals, significand: Decimal(string: max256ByteNumber.description)!) return maxInDecimal == self } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Error.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Error.swift index 064ced3ae2..9bd1e6cbc4 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Error.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Error.swift @@ -1,9 +1,7 @@ import Foundation extension Error { - var smartDescription: String { self is LocalizedError ? localizedDescription : "\(self)" } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/HudHelper.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/HudHelper.swift index 53fc39bb2b..9d7c6f086b 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/HudHelper.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/HudHelper.swift @@ -1,10 +1,9 @@ -import Foundation -import UIKit import ComponentKit +import Foundation import HUD +import UIKit extension HudHelper { - enum BannerType { case addedToWatchlist case removedFromWatchlist @@ -75,7 +74,7 @@ extension HudHelper { var color: UIColor { switch self { case .addedToWatchlist, .alreadyAddedToWallet, .notSupportedYet, .sent, .swapped, .approved, .revoked, .attention: return .themeJacob - case .removedFromWallet, .removedFromWatchlist, .deleted, .noInternet, .disconnectedWalletConnect, .error: return .themeLucian + case .removedFromWallet, .removedFromWatchlist, .deleted, .noInternet, .disconnectedWalletConnect, .error: return .themeLucian case .addedToWallet, .copied, .saved, .savedToCloud, .done, .restored, .created, .imported, .walletAdded, .enabled, .success: return .themeRemus case .waitingForSession, .disconnectingWalletConnect, .enabling, .sending, .swapping, .approving, .revoking: return .themeGray } @@ -103,7 +102,7 @@ extension HudHelper { case .disconnectingWalletConnect: return "alert.disconnecting".localized case .disconnectedWalletConnect: return "alert.disconnected".localized case .enabling: return "alert.enabling".localized - case .enabled(let count): return "alert.enabled_coins".localized(count) + case let .enabled(count): return "alert.enabled_coins".localized(count) case .sending: return "alert.sending".localized case .sent: return "alert.sent".localized case .swapping: return "alert.swapping".localized @@ -112,9 +111,9 @@ extension HudHelper { case .approved: return "alert.approved".localized case .revoking: return "alert.revoking".localized case .revoked: return "alert.revoked".localized - case .success(let description): return description - case .attention(let description): return description - case .error(let description): return description + case let .success(description): return description + case let .attention(description): return description + case let .error(description): return description } } @@ -145,7 +144,6 @@ extension HudHelper { default: return true } } - } func show(banner: BannerType) { @@ -167,15 +165,14 @@ extension HudHelper { config.cornerRadius = 28 let viewItem = HUD.ViewItem( - icon: banner.icon, - iconColor: banner.color, - title: banner.title, - showingTime: banner.showingTime, - isLoading: banner.isLoading + icon: banner.icon, + iconColor: banner.color, + title: banner.title, + showingTime: banner.showingTime, + isLoading: banner.isLoading ) - let statusBarStyle = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.windowScene?.statusBarManager?.statusBarStyle + let statusBarStyle = UIApplication.shared.windows.filter(\.isKeyWindow).first?.windowScene?.statusBarManager?.statusBarStyle HUD.instance.show(config: config, viewItem: viewItem, statusBarStyle: statusBarStyle, forced: banner.forced) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Integer.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Integer.swift index 594e93d758..ec459bebad 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Integer.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/Integer.swift @@ -1,7 +1,6 @@ import Foundation extension Int { - var digits: Int { guard self != 0 else { return 0 @@ -14,5 +13,4 @@ extension Int { let digitCount: Int = Swift.max(0, digits - depth) return (pow(Decimal(10), digitCount) as NSDecimalNumber).intValue } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/NSAttributedString.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/NSAttributedString.swift index 99edab08c3..afbe016899 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/NSAttributedString.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/NSAttributedString.swift @@ -1,19 +1,17 @@ import UIKit -extension NSAttributedString { - - public func height(containerWidth: CGFloat) -> CGFloat { +public extension NSAttributedString { + func height(containerWidth: CGFloat) -> CGFloat { size(containerWidth: containerWidth).height } - public func size(containerWidth: CGFloat) -> CGSize { - let size = self.boundingRect( - with: CGSize(width: containerWidth, height: .greatestFiniteMagnitude), - options: [.usesFontLeading, .usesLineFragmentOrigin], - context: nil + func size(containerWidth: CGFloat) -> CGSize { + let size = boundingRect( + with: CGSize(width: containerWidth, height: .greatestFiniteMagnitude), + options: [.usesFontLeading, .usesLineFragmentOrigin], + context: nil ).size return CGSize(width: ceil(size.width), height: ceil(size.height)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/SectionsTableView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/SectionsTableView.swift index 853db2af1c..205db51bcc 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/SectionsTableView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/SectionsTableView.swift @@ -1,17 +1,16 @@ -import UIKit -import SectionsTableView import ComponentKit +import SectionsTableView import ThemeKit +import UIKit extension SectionsTableView { - func sectionHeader(text: String, height: CGFloat? = nil, backgroundColor: UIColor = .clear) -> ViewState { registerHeaderFooter(forClass: SubtitleHeaderFooterView.self) return .cellType( - hash: text, - binder: { $0.bind(text: text, backgroundColor: backgroundColor) }, - dynamicHeight: { _ in height ?? SubtitleHeaderFooterView.height } + hash: text, + binder: { $0.bind(text: text, backgroundColor: backgroundColor) }, + dynamicHeight: { _ in height ?? SubtitleHeaderFooterView.height } ) } @@ -19,11 +18,11 @@ extension SectionsTableView { registerHeaderFooter(forClass: BottomDescriptionHeaderFooterView.self) return .cellType( - hash: text, - binder: { - $0.bind(text: text, textColor: textColor, topMargin: topMargin, bottomMargin: bottomMargin) - }, - dynamicHeight: { BottomDescriptionHeaderFooterView.height(containerWidth: $0, text: text, topMargin: topMargin, bottomMargin: bottomMargin) } + hash: text, + binder: { + $0.bind(text: text, textColor: textColor, topMargin: topMargin, bottomMargin: bottomMargin) + }, + dynamicHeight: { BottomDescriptionHeaderFooterView.height(containerWidth: $0, text: text, topMargin: topMargin, bottomMargin: bottomMargin) } ) } @@ -31,42 +30,42 @@ extension SectionsTableView { registerCell(forClass: HighlightedDescriptionCell.self) return Row( - id: id, - dynamicHeight: { width in - HighlightedDescriptionCell.height(containerWidth: width, text: text, ignoreBottomMargin: ignoreBottomMargin, topVerticalMargin: topVerticalMargin ?? HighlightedDescriptionCell.defaultVerticalMargin) - }, - bind: { cell, _ in - cell.set(style: style) - cell.descriptionText = text - if let topVerticalMargin { - cell.set(verticalMargin: topVerticalMargin) - } + id: id, + dynamicHeight: { width in + HighlightedDescriptionCell.height(containerWidth: width, text: text, ignoreBottomMargin: ignoreBottomMargin, topVerticalMargin: topVerticalMargin ?? HighlightedDescriptionCell.defaultVerticalMargin) + }, + bind: { cell, _ in + cell.set(style: style) + cell.descriptionText = text + if let topVerticalMargin { + cell.set(verticalMargin: topVerticalMargin) } + } ) } - func headerInfoRow(id: String, title: String, topSeparator: Bool = true, infoAction: (() -> ())? = nil) -> RowProtocol { + func headerInfoRow(id: String, title: String, topSeparator: Bool = true, infoAction: (() -> Void)? = nil) -> RowProtocol { var elements: [CellBuilderNew.CellElement] = [ - .textElement(text: .body(title)) + .textElement(text: .body(title)), ] if let infoAction { elements.append( - .secondaryCircleButton { component in - component.button.set(image: UIImage(named: "circle_information_20"), style: .transparent) - component.onTap = infoAction - } + .secondaryCircleButton { component in + component.button.set(image: UIImage(named: "circle_information_20"), style: .transparent) + component.onTap = infoAction + } ) } return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: self, - id: id, - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .transparent, isFirst: !topSeparator) - } + rootElement: .hStack(elements), + tableView: self, + id: id, + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .transparent, isFirst: !topSeparator) + } ) } @@ -74,64 +73,64 @@ extension SectionsTableView { registerCell(forClass: DescriptionCell.self) return Row( - id: id, - dynamicHeight: { containerWidth in - DescriptionCell.height(containerWidth: containerWidth, text: text, font: font, ignoreBottomMargin: ignoreBottomMargin) - }, - bind: { cell, _ in - cell.label.text = text - if let font = font { - cell.label.font = font - } - if let textColor = textColor { - cell.label.textColor = textColor - } + id: id, + dynamicHeight: { containerWidth in + DescriptionCell.height(containerWidth: containerWidth, text: text, font: font, ignoreBottomMargin: ignoreBottomMargin) + }, + bind: { cell, _ in + cell.label.text = text + if let font { + cell.label.font = font + } + if let textColor { + cell.label.textColor = textColor } + } ) } func subtitleRow(text: String) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .text { (component: TextComponent) -> () in - component.font = .body - component.textColor = .themeLeah - component.text = text - } - ]), - tableView: self, - id: "subtitle_\(text)", - hash: text, - height: .heightCell48, - bind: { cell in - cell.set(backgroundStyle: .transparent) - cell.selectionStyle = .none - } + rootElement: .hStack([ + .text { (component: TextComponent) in + component.font = .body + component.textColor = .themeLeah + component.text = text + }, + ]), + tableView: self, + id: "subtitle_\(text)", + hash: text, + height: .heightCell48, + bind: { cell in + cell.set(backgroundStyle: .transparent) + cell.selectionStyle = .none + } ) } - func subtitleWithInfoButtonRow(text: String, uppercase: Bool = true, action: @escaping () -> ()) -> RowProtocol { + func subtitleWithInfoButtonRow(text: String, uppercase: Bool = true, action: @escaping () -> Void) -> RowProtocol { CellBuilderNew.row( - rootElement: .hStack([ - .text { (component: TextComponent) -> () in - component.font = .subhead1 - component.textColor = .themeGray - component.text = uppercase ? text.uppercased() : text - }, - .image20 { (component: ImageComponent) -> () in - component.imageView.image = UIImage(named: "circle_information_20")?.withTintColor(.themeGray) - } - ]), - layoutMargins: UIEdgeInsets(top: 0, left: .margin32, bottom: 0, right: .margin32), - tableView: self, - id: "subtitle-\(text)", - height: .margin32, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .transparent, isFirst: true) - cell.selectionStyle = .none + rootElement: .hStack([ + .text { (component: TextComponent) in + component.font = .subhead1 + component.textColor = .themeGray + component.text = uppercase ? text.uppercased() : text + }, + .image20 { (component: ImageComponent) in + component.imageView.image = UIImage(named: "circle_information_20")?.withTintColor(.themeGray) }, - action: action + ]), + layoutMargins: UIEdgeInsets(top: 0, left: .margin32, bottom: 0, right: .margin32), + tableView: self, + id: "subtitle-\(text)", + height: .margin32, + autoDeselect: true, + bind: { cell in + cell.set(backgroundStyle: .transparent, isFirst: true) + cell.selectionStyle = .none + }, + action: action ) } @@ -140,49 +139,48 @@ extension SectionsTableView { let font: UIFont = .caption return CellBuilderNew.row( - rootElement: .hStack([ - .text { component in - component.font = font - component.textColor = .themeLeah - component.text = text - component.numberOfLines = 0 - } - ]), - tableView: self, - id: "message", - hash: text, - autoDeselect: true, - dynamicHeight: { containerWidth in - CellBuilderNew.height( - containerWidth: containerWidth, - backgroundStyle: backgroundStyle, - text: text, - font: font, - elements: [.multiline] - ) + rootElement: .hStack([ + .text { component in + component.font = font + component.textColor = .themeLeah + component.text = text + component.numberOfLines = 0 }, - bind: { cell in - cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) - }, - action: { - CopyHelper.copyAndNotify(value: text) - } + ]), + tableView: self, + id: "message", + hash: text, + autoDeselect: true, + dynamicHeight: { containerWidth in + CellBuilderNew.height( + containerWidth: containerWidth, + backgroundStyle: backgroundStyle, + text: text, + font: font, + elements: [.multiline] + ) + }, + bind: { cell in + cell.set(backgroundStyle: .lawrence, isFirst: true, isLast: true) + }, + action: { + CopyHelper.copyAndNotify(value: text) + } ) } - } extension SectionsTableView { -// complete layout for more frequency used layouts + // complete layout for more frequency used layouts // layout for standard cell with 24pt image func universalImage24Elements(image: CellBuilderNew.CellElement.Image? = nil, title: CellBuilderNew.CellElement.Text? = nil, value: CellBuilderNew.CellElement.Text? = nil, accessoryType: CellBuilderNew.CellElement.AccessoryType = .none) -> [CellBuilderNew.CellElement] { var elements = [CellBuilderNew.CellElement]() elements.append(.imageElement(image: image, size: .image24)) - if let title = title { + if let title { elements.append(.textElement(text: title)) } - if let value = value { + if let value { elements.append(.textElement(text: value, parameters: .allCompression)) } elements.append(contentsOf: CellBuilderNew.CellElement.accessoryElements(accessoryType)) @@ -194,94 +192,91 @@ extension SectionsTableView { var elements = [CellBuilderNew.CellElement]() elements.append(.imageElement(image: image, size: .image32)) - if let title = title { + if let title { var verticalTexts = [CellBuilderNew.CellElement]() verticalTexts.append(.textElement(text: title)) - if let description = description { + if let description { verticalTexts.append(.margin(1)) verticalTexts.append(.textElement(text: description)) } elements.append(.vStackCentered(verticalTexts)) } - if let value = value { + if let value { elements.append(.textElement(text: value, parameters: .allCompression)) } elements.append(contentsOf: CellBuilderNew.CellElement.accessoryElements(accessoryType)) return elements } - } extension SectionsTableView { - // universal cell with image24, text, value and accessory for 48 height - func universalRow48(id: String, image: CellBuilderNew.CellElement.Image? = nil, title: CellBuilderNew.CellElement.Text? = nil, value: CellBuilderNew.CellElement.Text? = nil, accessoryType: CellBuilderNew.CellElement.AccessoryType = .none, hash: String? = nil, backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence, autoDeselect: Bool = false, isFirst: Bool = false, isLast: Bool = false, action: (() -> ())? = nil) -> RowProtocol { + func universalRow48(id: String, image: CellBuilderNew.CellElement.Image? = nil, title: CellBuilderNew.CellElement.Text? = nil, value: CellBuilderNew.CellElement.Text? = nil, accessoryType: CellBuilderNew.CellElement.AccessoryType = .none, hash: String? = nil, backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence, autoDeselect: Bool = false, isFirst: Bool = false, isLast: Bool = false, action: (() -> Void)? = nil) -> RowProtocol { let elements = universalImage24Elements(image: image, title: title, value: value, accessoryType: accessoryType) return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: self, - id: id, - hash: hash, - height: .heightCell48, - autoDeselect: autoDeselect, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) - }, - action: action + rootElement: .hStack(elements), + tableView: self, + id: id, + hash: hash, + height: .heightCell48, + autoDeselect: autoDeselect, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + }, + action: action ) } // universal cell with image32, text, value and accessory for 56 height - func universalRow56(id: String, image: CellBuilderNew.CellElement.Image? = nil, title: CellBuilderNew.CellElement.Text? = nil, value: CellBuilderNew.CellElement.Text? = nil, accessoryType: CellBuilderNew.CellElement.AccessoryType = .none, hash: String? = nil, backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence, autoDeselect: Bool = false, isFirst: Bool = false, isLast: Bool = false, action: (() -> ())? = nil) -> RowProtocol { + func universalRow56(id: String, image: CellBuilderNew.CellElement.Image? = nil, title: CellBuilderNew.CellElement.Text? = nil, value: CellBuilderNew.CellElement.Text? = nil, accessoryType: CellBuilderNew.CellElement.AccessoryType = .none, hash: String? = nil, backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence, autoDeselect: Bool = false, isFirst: Bool = false, isLast: Bool = false, action: (() -> Void)? = nil) -> RowProtocol { let elements = universalImage32Elements(image: image, title: title, value: value, accessoryType: accessoryType) return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: self, - id: id, - hash: hash, - height: .heightCell56, - autoDeselect: autoDeselect, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) - }, - action: action + rootElement: .hStack(elements), + tableView: self, + id: id, + hash: hash, + height: .heightCell56, + autoDeselect: autoDeselect, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + }, + action: action ) } // universal cell with image32, multi-text, value and accessory for 62 height func universalRow62( - id: String, - image: CellBuilderNew.CellElement.Image? = nil, - title: CellBuilderNew.CellElement.Text? = nil, - description: CellBuilderNew.CellElement.Text? = nil, - value: CellBuilderNew.CellElement.Text? = nil, - accessoryType: CellBuilderNew.CellElement.AccessoryType = .none, - hash: String? = nil, - backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence, - autoDeselect: Bool = false, - rowActionProvider: (() -> [RowAction])? = nil, - isFirst: Bool = false, - isLast: Bool = false, - action: (() -> ())? = nil + id: String, + image: CellBuilderNew.CellElement.Image? = nil, + title: CellBuilderNew.CellElement.Text? = nil, + description: CellBuilderNew.CellElement.Text? = nil, + value: CellBuilderNew.CellElement.Text? = nil, + accessoryType: CellBuilderNew.CellElement.AccessoryType = .none, + hash: String? = nil, + backgroundStyle: BaseThemeCell.BackgroundStyle = .lawrence, + autoDeselect: Bool = false, + rowActionProvider: (() -> [RowAction])? = nil, + isFirst: Bool = false, + isLast: Bool = false, + action: (() -> Void)? = nil ) -> RowProtocol { let elements = universalImage32Elements(image: image, title: title, description: description, value: value, accessoryType: accessoryType) return CellBuilderNew.row( - rootElement: .hStack(elements), - tableView: self, - id: id, - hash: hash, - height: .heightDoubleLineCell, - autoDeselect: autoDeselect, - rowActionProvider: rowActionProvider, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) - }, - action: action + rootElement: .hStack(elements), + tableView: self, + id: id, + hash: hash, + height: .heightDoubleLineCell, + autoDeselect: autoDeselect, + rowActionProvider: rowActionProvider, + bind: { cell in + cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) + }, + action: action ) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/String.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/String.swift index 22693f55cc..0f456446df 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/String.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/String.swift @@ -1,7 +1,6 @@ extension String { - func stripping(prefix: String?) -> String { - if let prefix = prefix, hasPrefix(prefix) { + if let prefix, hasPrefix(prefix) { return String(dropFirst(prefix.count)) } @@ -22,7 +21,6 @@ extension String { return String(prefix(extraPrefix + 4)) + "..." + String(suffix(4)) } - } extension String: Identifiable { diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/TimeInterval.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/TimeInterval.swift index 8d5b666962..63159887e7 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/TimeInterval.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/TimeInterval.swift @@ -1,7 +1,6 @@ import Foundation extension TimeInterval { - var approximateHoursOrMinutes: String { let seconds = Int(self) let hours = seconds / 3600 @@ -13,5 +12,4 @@ extension TimeInterval { let minutes = seconds / 60 return "send.duration.minutes".localized(minutes) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIAlertController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIAlertController.swift index 88f465dc0d..19f54d6ace 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIAlertController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIAlertController.swift @@ -3,11 +3,10 @@ import UIKit private var window: UIWindow! extension UIAlertController { - public static func showSimpleAlert(fromController: UIViewController? = nil, title: String? = nil, message: String? = nil) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - let ok = UIAlertAction(title: "button.ok".localized, style: .cancel, handler:nil) + let ok = UIAlertAction(title: "button.ok".localized, style: .cancel, handler: nil) alert.addAction(ok) alert.show(forView: nil, barButtonItem: nil, fromController: fromController, sourceRect: nil) @@ -31,16 +30,15 @@ extension UIAlertController { } popoverPresentationController?.barButtonItem = barButtonItem - if let fromController = fromController { + if let fromController { fromController.present(self, animated: true) } else { window.rootViewController?.present(self, animated: true, completion: nil) } } - open override func viewDidDisappear(_ animated: Bool) { + override open func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) window = nil } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIDevice.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIDevice.swift index 64c18359ab..2ee0e6775e 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIDevice.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIDevice.swift @@ -1,7 +1,6 @@ import UIKit public extension UIDevice { - static let modelName: String = { var systemInfo = utsname() uname(&systemInfo) @@ -13,68 +12,67 @@ public extension UIDevice { func mapToDevice(identifier: String) -> String { // swiftlint:disable:this cyclomatic_complexity #if os(iOS) - switch identifier { - case "iPod5,1": return "iPod touch (5th generation)" - case "iPod7,1": return "iPod touch (6th generation)" - case "iPod9,1": return "iPod touch (7th generation)" - case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" - case "iPhone4,1": return "iPhone 4s" - case "iPhone5,1", "iPhone5,2": return "iPhone 5" - case "iPhone5,3", "iPhone5,4": return "iPhone 5c" - case "iPhone6,1", "iPhone6,2": return "iPhone 5s" - case "iPhone7,2": return "iPhone 6" - case "iPhone7,1": return "iPhone 6 Plus" - case "iPhone8,1": return "iPhone 6s" - case "iPhone8,2": return "iPhone 6s Plus" - case "iPhone9,1", "iPhone9,3": return "iPhone 7" - case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" - case "iPhone8,4": return "iPhone SE" - case "iPhone10,1", "iPhone10,4": return "iPhone 8" - case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" - case "iPhone10,3", "iPhone10,6": return "iPhone X" - case "iPhone11,2": return "iPhone XS" - case "iPhone11,4", "iPhone11,6": return "iPhone XS Max" - case "iPhone11,8": return "iPhone XR" - case "iPhone12,1": return "iPhone 11" - case "iPhone12,3": return "iPhone 11 Pro" - case "iPhone12,5": return "iPhone 11 Pro Max" - case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2" - case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3" - case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4" - case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" - case "iPad5,3", "iPad5,4": return "iPad Air 2" - case "iPad6,11", "iPad6,12": return "iPad 5" - case "iPad7,5", "iPad7,6": return "iPad 6" - case "iPad7,11", "iPad7,12": return "iPad 7" - case "iPad11,4", "iPad11,5": return "iPad Air (3rd generation)" - case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini" - case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad Mini 2" - case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad Mini 3" - case "iPad5,1", "iPad5,2": return "iPad Mini 4" - case "iPad11,1", "iPad11,2": return "iPad Mini 5" - case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" - case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch)" - case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)" - case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" - case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4":return "iPad Pro (11-inch)" - case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8":return "iPad Pro (12.9-inch) (3rd generation)" - case "AppleTV5,3": return "Apple TV" - case "AppleTV6,2": return "Apple TV 4K" - case "AudioAccessory1,1": return "HomePod" - case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))" - default: return identifier - } + switch identifier { + case "iPod5,1": return "iPod touch (5th generation)" + case "iPod7,1": return "iPod touch (6th generation)" + case "iPod9,1": return "iPod touch (7th generation)" + case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" + case "iPhone4,1": return "iPhone 4s" + case "iPhone5,1", "iPhone5,2": return "iPhone 5" + case "iPhone5,3", "iPhone5,4": return "iPhone 5c" + case "iPhone6,1", "iPhone6,2": return "iPhone 5s" + case "iPhone7,2": return "iPhone 6" + case "iPhone7,1": return "iPhone 6 Plus" + case "iPhone8,1": return "iPhone 6s" + case "iPhone8,2": return "iPhone 6s Plus" + case "iPhone9,1", "iPhone9,3": return "iPhone 7" + case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" + case "iPhone8,4": return "iPhone SE" + case "iPhone10,1", "iPhone10,4": return "iPhone 8" + case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" + case "iPhone10,3", "iPhone10,6": return "iPhone X" + case "iPhone11,2": return "iPhone XS" + case "iPhone11,4", "iPhone11,6": return "iPhone XS Max" + case "iPhone11,8": return "iPhone XR" + case "iPhone12,1": return "iPhone 11" + case "iPhone12,3": return "iPhone 11 Pro" + case "iPhone12,5": return "iPhone 11 Pro Max" + case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return "iPad 2" + case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3" + case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4" + case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" + case "iPad5,3", "iPad5,4": return "iPad Air 2" + case "iPad6,11", "iPad6,12": return "iPad 5" + case "iPad7,5", "iPad7,6": return "iPad 6" + case "iPad7,11", "iPad7,12": return "iPad 7" + case "iPad11,4", "iPad11,5": return "iPad Air (3rd generation)" + case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini" + case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad Mini 2" + case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad Mini 3" + case "iPad5,1", "iPad5,2": return "iPad Mini 4" + case "iPad11,1", "iPad11,2": return "iPad Mini 5" + case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" + case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch)" + case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)" + case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" + case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return "iPad Pro (11-inch)" + case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return "iPad Pro (12.9-inch) (3rd generation)" + case "AppleTV5,3": return "Apple TV" + case "AppleTV6,2": return "Apple TV 4K" + case "AudioAccessory1,1": return "HomePod" + case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))" + default: return identifier + } #elseif os(tvOS) - switch identifier { - case "AppleTV5,3": return "Apple TV 4" - case "AppleTV6,2": return "Apple TV 4K" - case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))" - default: return identifier - } + switch identifier { + case "AppleTV5,3": return "Apple TV 4" + case "AppleTV6,2": return "Apple TV 4K" + case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))" + default: return identifier + } #endif } return mapToDevice(identifier: identifier) }() - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIImage.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIImage.swift index 1511637f9c..f9b7d47826 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIImage.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIImage.swift @@ -1,8 +1,7 @@ -import UIKit import MarketKit +import UIKit extension UIImage { - static func qrCodeImage(qrCodeString: String, size: CGFloat) -> UIImage? { let data = qrCodeString.data(using: .utf8) @@ -38,5 +37,4 @@ extension UIImage { UIGraphicsEndImageContext() return image } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITabBarItem.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITabBarItem.swift index ffdb7fa6b7..982f03b9a7 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITabBarItem.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITabBarItem.swift @@ -1,7 +1,6 @@ import UIKit extension UITabBarItem { - func setDotBadge(visible: Bool, count: Int) { guard visible else { badgeValue = nil @@ -18,5 +17,4 @@ extension UITabBarItem { setBadgeTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], for: .normal) } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITextView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITextView.swift index 192ece5fb9..a09461f7c3 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITextView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UITextView.swift @@ -1,7 +1,6 @@ import UIKit extension UITextView { - static var appDebug: UITextView { let textView = UITextView() @@ -13,15 +12,14 @@ extension UITextView { return textView } - } extension UITextField { - func textRange(range: NSRange) -> UITextRange? { let beginning = beginningOfDocument guard let start = position(from: beginning, offset: range.location), - let end = position(from: start, offset: range.length) else { + let end = position(from: start, offset: range.length) + else { return nil } @@ -33,5 +31,4 @@ extension UITextField { let length = offset(from: textRange.start, to: textRange.end) return NSRange(location: location, length: length) } - -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIViewController.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIViewController.swift index 03cf30c4d1..3894313af7 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/Extensions/UIViewController.swift @@ -1,7 +1,6 @@ import UIKit extension UIViewController { - var visibleController: UIViewController { var controller: UIViewController = self while let presentedController = controller.presentedViewController { @@ -12,9 +11,8 @@ extension UIViewController { } static var visibleController: UIViewController? { - let keyWindow = UIApplication.shared.windows.filter { $0.isKeyWindow }.first + let keyWindow = UIApplication.shared.windows.filter(\.isKeyWindow).first return keyWindow?.rootViewController?.visibleController } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientClippingView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientClippingView.swift index b5663cb8d0..9ad5f40dfd 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientClippingView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientClippingView.swift @@ -23,7 +23,8 @@ class GradientClippingView: UIView { layer.mask = maskLayer } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -40,5 +41,4 @@ class GradientClippingView: UIView { layer.mask = nil } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientLayer.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientLayer.swift index 7b7f259178..f8f8ac0771 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientLayer.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/GradientLayer.swift @@ -17,11 +17,11 @@ class GradientLayer: CALayer { name = GradientLayer.name } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func draw(in ctx: CGContext) { super.draw(in: ctx) @@ -36,21 +36,21 @@ class GradientLayer: CALayer { // 5 let gradient = CGGradient(colorsSpace: colorSpace, - colors: colors as CFArray, - locations: colorLocations)! + colors: colors as CFArray, + locations: colorLocations)! // 6 let startPoint = CGPoint(x: 0, y: 0) let endPoint = CGPoint(x: 0, y: bounds.height) ctx.drawLinearGradient(gradient, - start: startPoint, - end: endPoint, - options: []) + start: startPoint, + end: endPoint, + options: []) } static func appendLayer(to view: UIView?, fromColor: UIColor, toColor: UIColor, topOffset: CGFloat = 160) { - guard let view = view else { + guard let view else { return } if let sublayer = view.layer.sublayers?.first(where: { $0.name == GradientLayer.name }) { @@ -63,5 +63,4 @@ class GradientLayer: CALayer { view.layer.insertSublayer(layer, at: 0) layer.display() } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionBaseView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionBaseView.swift index 44e4b9a16c..0eae50a167 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionBaseView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionBaseView.swift @@ -1,12 +1,12 @@ -import UIKit import SwiftUI +import UIKit class HighlightedDescriptionBaseView: UIView { - internal static let font: UIFont = .subhead2 - internal static let sidePadding: CGFloat = .margin16 - internal static let verticalPadding: CGFloat = .margin12 + static let font: UIFont = .subhead2 + static let sidePadding: CGFloat = .margin16 + static let verticalPadding: CGFloat = .margin12 - internal let label = UILabel() + let label = UILabel() public init() { super.init(frame: .zero) @@ -21,7 +21,8 @@ class HighlightedDescriptionBaseView: UIView { label.setContentCompressionResistancePriority(.required, for: .vertical) } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -31,7 +32,7 @@ class HighlightedDescriptionBaseView: UIView { backgroundColor = .themeYellow20 borderColor = .themeYellowD case .red: - backgroundColor = UIColor(hex: 0xff4820, alpha: 0.2) + backgroundColor = UIColor(hex: 0xFF4820, alpha: 0.2) borderColor = .themeLucian } } @@ -40,11 +41,9 @@ class HighlightedDescriptionBaseView: UIView { get { label.text } set { label.text = newValue } } - } extension HighlightedDescriptionBaseView { - enum Style: String { case yellow case red @@ -56,5 +55,4 @@ extension HighlightedDescriptionBaseView { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionView.swift index 3acf13aea1..9977ee78e8 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/HighlightedDescriptionView.swift @@ -1,8 +1,7 @@ -import UIKit import SnapKit +import UIKit class HighlightedDescriptionView: HighlightedDescriptionBaseView { - override public init() { super.init() @@ -17,17 +16,15 @@ class HighlightedDescriptionView: HighlightedDescriptionBaseView { label.textColor = .themeLeah } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - } extension HighlightedDescriptionView { - public static func height(containerWidth: CGFloat, text: String) -> CGFloat { let textHeight = text.height(forContainerWidth: containerWidth - 2 * sidePadding, font: font) return textHeight + 2 * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/KeyboardTracker/PseudoAccessoryView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/KeyboardTracker/PseudoAccessoryView.swift index 48716bbb9c..30c2756d17 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/KeyboardTracker/PseudoAccessoryView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/KeyboardTracker/PseudoAccessoryView.swift @@ -39,14 +39,14 @@ public class PseudoAccessoryView: UIView { self.heightConstraint = heightConstraint self.heightConstraint?.constant = heightValue - if let superview = superview { + if let superview { // delegate?.pseudoAccessoryView(self, keyboardFrameDidChange: superview.frame) superview.addObserver(self, forKeyPath: keyPathSelector, context: nil) } } - override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - if let superview = superview, object as? UIView == superview, keyPath == keyPathSelector, superview.frame != oldFrame { + override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) { + if let superview, object as? UIView == superview, keyPath == keyPathSelector, superview.frame != oldFrame { oldFrame = superview.frame delegate?.pseudoAccessoryView(self, keyboardFrameDidChange: superview.frame) } @@ -55,5 +55,4 @@ public class PseudoAccessoryView: UIView { deinit { superview?.removeObserver(self, forKeyPath: keyPathSelector) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ScanQr/ScanQrView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ScanQr/ScanQrView.swift index 73ac1ede5e..54e48b4b64 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ScanQr/ScanQrView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ScanQr/ScanQrView.swift @@ -108,7 +108,7 @@ class ScanQrView: UIView { } private func updateRectOfInterest() { - guard !width.isZero && !height.isZero else { + guard !width.isZero, !height.isZero else { return } @@ -155,7 +155,7 @@ class ScanQrView: UIView { } func startCaptureSession() { - if let captureSession = captureSession, !captureSession.isRunning { + if let captureSession, !captureSession.isRunning { DispatchQueue.main.async { captureSession.startRunning() } @@ -163,7 +163,7 @@ class ScanQrView: UIView { } func stop() { - if let captureSession = captureSession, captureSession.isRunning { + if let captureSession, captureSession.isRunning { captureSession.stopRunning() } } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Alert.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Alert.swift index bbb28458ba..175721bd37 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Alert.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Alert.swift @@ -20,4 +20,4 @@ struct AlertButtonTintColor: ViewModifier { UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = previousTintColor } } -} \ No newline at end of file +} diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/BottomGradientWrapper.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/BottomGradientWrapper.swift index bcae4b7701..c5af015933 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/BottomGradientWrapper.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/BottomGradientWrapper.swift @@ -13,7 +13,7 @@ struct BottomGradientWrapper: View { VStack { Spacer() - LinearGradient(colors: [.themeTyler, Color.themeTyler.opacity(0)], startPoint: .bottom, endPoint: .top) + LinearGradient(colors: [.themeTyler, Color.themeTyler.opacity(0)], startPoint: .bottom, endPoint: .top) .frame(maxWidth: .infinity) .frame(height: .margin16) } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/HighlightedTextView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/HighlightedTextView.swift index e630b25025..e4432fd5a5 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/HighlightedTextView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/HighlightedTextView.swift @@ -19,20 +19,18 @@ struct HighlightedTextView: View { var body: some View { Text(text) - .padding(EdgeInsets(top: .margin12, leading: .margin16, bottom: .margin12, trailing: .margin16)) - .frame(maxWidth: .infinity, alignment: .leading) - .foregroundColor(.themeBran) - .font(.themeSubhead2) - .background(RoundedRectangle(cornerRadius: .cornerRadius12, style: .continuous).fill(style.color.opacity(0.2))) - .overlay( - RoundedRectangle(cornerRadius: .cornerRadius12, style: .continuous).stroke(style.color, lineWidth: .heightOneDp) - ) + .padding(EdgeInsets(top: .margin12, leading: .margin16, bottom: .margin12, trailing: .margin16)) + .frame(maxWidth: .infinity, alignment: .leading) + .foregroundColor(.themeBran) + .font(.themeSubhead2) + .background(RoundedRectangle(cornerRadius: .cornerRadius12, style: .continuous).fill(style.color.opacity(0.2))) + .overlay( + RoundedRectangle(cornerRadius: .cornerRadius12, style: .continuous).stroke(style.color, lineWidth: .heightOneDp) + ) } - } extension HighlightedTextView { - enum Style { case warning case alert @@ -44,5 +42,4 @@ extension HighlightedTextView { } } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionFooter.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionFooter.swift index 6a045caa3e..287bdcec00 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionFooter.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionFooter.swift @@ -5,8 +5,7 @@ struct ListSectionFooter: View { var body: some View { Text(text) - .themeSubhead2() - .padding(EdgeInsets(top: .margin12, leading: .margin16, bottom: 0, trailing: .margin16)) + .themeSubhead2() + .padding(EdgeInsets(top: .margin12, leading: .margin16, bottom: 0, trailing: .margin16)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionHeader.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionHeader.swift index 46dbccee6c..780a96426d 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionHeader.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionHeader.swift @@ -5,9 +5,8 @@ struct ListSectionHeader: View { var body: some View { Text(text.uppercased()) - .themeSubhead1() - .frame(height: .margin32) - .padding(EdgeInsets(top: 0, leading: .margin16, bottom: 0, trailing: .margin16)) + .themeSubhead1() + .frame(height: .margin32) + .padding(EdgeInsets(top: 0, leading: .margin16, bottom: 0, trailing: .margin16)) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionInfoHeader.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionInfoHeader.swift index b9e5f14081..cb42939b75 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionInfoHeader.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/ListSectionInfoHeader.swift @@ -9,16 +9,15 @@ struct ListSectionInfoHeader: View { Button(action: action) { HStack { Text(text.uppercased()) - .font(.themeSubhead1) - .foregroundColor(.themeGray) + .font(.themeSubhead1) + .foregroundColor(.themeGray) Image("circle_information_20").themeIcon() } } - .frame(height: .margin32) - .padding(EdgeInsets(top: 0, leading: .margin16, bottom: 0, trailing: .margin16)) + .frame(height: .margin32) + .padding(EdgeInsets(top: 0, leading: .margin16, bottom: 0, trailing: .margin16)) Spacer() } } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryButtonStyle.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryButtonStyle.swift index 76c10851d4..9bf0dbe629 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryButtonStyle.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryButtonStyle.swift @@ -1,5 +1,5 @@ -import SwiftUI import ComponentKit +import SwiftUI struct PrimaryButtonStyle: ButtonStyle { let style: Style diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryCircleButtonStyle.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryCircleButtonStyle.swift index 42e4e1972a..96f89f225b 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryCircleButtonStyle.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/PrimaryCircleButtonStyle.swift @@ -1,5 +1,5 @@ -import SwiftUI import ComponentKit +import SwiftUI struct PrimaryCircleButtonStyle: ButtonStyle { let style: Style diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/SecondaryCircleButtonStyle.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/SecondaryCircleButtonStyle.swift index 0960a67cc0..c506e248fb 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/SecondaryCircleButtonStyle.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/SecondaryCircleButtonStyle.swift @@ -7,11 +7,11 @@ struct SecondaryCircleButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label - .padding(.margin4) - .foregroundColor(style.foregroundColor(isEnabled: isEnabled, isPressed: configuration.isPressed)) - .background(style.backgroundColor(isEnabled: isEnabled, isPressed: configuration.isPressed)) - .clipShape(Circle()) - .animation(.easeOut(duration: 0.2), value: configuration.isPressed) + .padding(.margin4) + .foregroundColor(style.foregroundColor(isEnabled: isEnabled, isPressed: configuration.isPressed)) + .background(style.backgroundColor(isEnabled: isEnabled, isPressed: configuration.isPressed)) + .clipShape(Circle()) + .animation(.easeOut(duration: 0.2), value: configuration.isPressed) } enum Style { diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Shake.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Shake.swift index 7c6c3a63f4..85ffaaa87f 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Shake.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/Shake.swift @@ -45,11 +45,11 @@ struct Shake: View { private func backAndForthAnimation(duration: CGFloat, offset: CGFloat) async { let halfDuration = duration / 2 await animate(duration: halfDuration) { - self.xOffset = offset + xOffset = offset } await animate(duration: halfDuration) { - self.xOffset = -offset + xOffset = -offset } } } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/TitledHighlightedDescriptionView.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/TitledHighlightedDescriptionView.swift index 0d51fabad7..94bad9dc73 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/TitledHighlightedDescriptionView.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/TitledHighlightedDescriptionView.swift @@ -1,5 +1,5 @@ -import UIKit import SnapKit +import UIKit class TitledHighlightedDescriptionView: HighlightedDescriptionBaseView { private let titleIconImageView = UIImageView() @@ -7,8 +7,8 @@ class TitledHighlightedDescriptionView: HighlightedDescriptionBaseView { private let closeButton = UIButton() private let backgroundButton = UIButton() - var onTapClose: (() -> ())? - var onTapBackground: (() -> ())? + var onTapClose: (() -> Void)? + var onTapBackground: (() -> Void)? override public init() { super.init() @@ -60,7 +60,8 @@ class TitledHighlightedDescriptionView: HighlightedDescriptionBaseView { label.textColor = .themeLeah } - required public init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -94,10 +95,8 @@ class TitledHighlightedDescriptionView: HighlightedDescriptionBaseView { } extension TitledHighlightedDescriptionView { - @objc public class func height(containerWidth: CGFloat, text: String) -> CGFloat { let textHeight = text.height(forContainerWidth: containerWidth - 2 * sidePadding, font: font) return verticalPadding + .iconSize20 + textHeight + 2 * verticalPadding } - } diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/ValueFormatter.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/ValueFormatter.swift index 93782b00f5..37d8c01375 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/ValueFormatter.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/ValueFormatter.swift @@ -26,8 +26,8 @@ class ValueFormatter { let digits: Int switch value { - case pow(10, basePow)..<(2 * pow(10, basePow + 1)): digits = 2 - case (2 * pow(10, basePow + 1))..<(2 * pow(10, basePow + 2)): digits = 1 + case pow(10, basePow) ..< (2 * pow(10, basePow + 1)): digits = 2 + case (2 * pow(10, basePow + 1)) ..< (2 * pow(10, basePow + 2)): digits = 1 default: digits = 0 } @@ -35,11 +35,11 @@ class ValueFormatter { } private func fractionZeroCount(value: Decimal, maxCount: Int) -> Int { - guard value > 0 && value < 1 else { + guard value > 0, value < 1 else { return 0 } - for count in 0..= 1 { return count } @@ -62,43 +62,43 @@ class ValueFormatter { case 0: digits = 0 - case 0..<0.0000_0001: + case 0 ..< 0.0000_0001: digits = 8 value = 0.0000_0001 tooSmall = true - case 0.0000_0001..<1: + case 0.0000_0001 ..< 1: let zeroCount = fractionZeroCount(value: value, maxCount: 8) digits = min(maxDigits, zeroCount + 4, 8) - case 1..<1.01: + case 1 ..< 1.01: digits = 4 - case 1.01..<1.1: + case 1.01 ..< 1.1: digits = 3 - case 1.1..<20: + case 1.1 ..< 20: digits = 2 - case 20..<200: + case 20 ..< 200: digits = 1 - case 200..<19_999.5: + case 200 ..< 19999.5: digits = 0 - case 19_999.5.. String { var string = string - if let suffix = suffix { + if let suffix { string = suffix.localized(string) } - if let symbol = symbol { + if let symbol { string = "\(string) \(symbol)" } - if let signValue = signValue { + if let signValue { var sign = "" if !signValue.isZero { sign = signValue.isSignMinus ? "-" : "+" @@ -175,7 +175,7 @@ class ValueFormatter { return currencyFormatter.string(from: 1 as NSDecimalNumber) } - guard let pattern = pattern else { + guard let pattern else { return nil } @@ -184,17 +184,15 @@ class ValueFormatter { return rawFormatter.string(from: value as NSDecimalNumber) } - guard let string = string else { + guard let string else { return nil } return pattern.replacingOccurrences(of: "1", with: decorated(string: string, suffix: suffix)) } - } extension ValueFormatter { - func formatShort(value: Decimal) -> String? { let (transformedValue, digits, suffix, tooSmall) = transformedShort(value: value) @@ -203,7 +201,7 @@ extension ValueFormatter { return rawFormatter.string(from: transformedValue as NSDecimalNumber) } - guard let string = string else { + guard let string else { return nil } @@ -218,7 +216,7 @@ extension ValueFormatter { return rawFormatter.string(from: transformedValue as NSDecimalNumber) } - guard let string = string else { + guard let string else { return nil } @@ -233,7 +231,7 @@ extension ValueFormatter { return rawFormatter.string(from: transformedValue as NSDecimalNumber) } - guard let string = string else { + guard let string else { return nil } @@ -284,11 +282,10 @@ extension ValueFormatter { return rawFormatter.string(from: transformedValue as NSDecimalNumber) } - guard let string = string else { + guard let string else { return nil } return decorated(string: string, signValue: showSign ? percentValue : nil) + "%" } - } diff --git a/UnstoppableWallet/Widget/CoinPriceList/CoinPriceListView.swift b/UnstoppableWallet/Widget/CoinPriceList/CoinPriceListView.swift index 1eb47ccdd6..f5eac4262e 100644 --- a/UnstoppableWallet/Widget/CoinPriceList/CoinPriceListView.swift +++ b/UnstoppableWallet/Widget/CoinPriceList/CoinPriceListView.swift @@ -146,7 +146,7 @@ struct CoinPriceListView: View { } @ViewBuilder private func icon(image: Image?) -> some View { - if let image = image { + if let image { image .resizable() .scaledToFit() diff --git a/UnstoppableWallet/Widget/Misc/ApiProvider.swift b/UnstoppableWallet/Widget/Misc/ApiProvider.swift index 8c77b2fd64..0006b9ba8e 100644 --- a/UnstoppableWallet/Widget/Misc/ApiProvider.swift +++ b/UnstoppableWallet/Widget/Misc/ApiProvider.swift @@ -121,12 +121,12 @@ struct ChartPoint: ImmutableMappable { enum Transform { static let stringToDecimalTransform: TransformOf = TransformOf(fromJSON: { string -> Decimal? in - guard let string = string else { + guard let string else { return nil } return Decimal(string: string) }, toJSON: { (value: Decimal?) in - guard let value = value else { + guard let value else { return nil } return value.description diff --git a/UnstoppableWallet/Widget/Misc/ValueFormatter.swift b/UnstoppableWallet/Widget/Misc/ValueFormatter.swift index 385b7d28bc..bf4aab165a 100644 --- a/UnstoppableWallet/Widget/Misc/ValueFormatter.swift +++ b/UnstoppableWallet/Widget/Misc/ValueFormatter.swift @@ -18,7 +18,7 @@ enum ValueFormatter { }() private static func fractionZeroCount(value: Decimal, maxCount: Int) -> Int { - guard value > 0 && value < 1 else { + guard value > 0, value < 1 else { return 0 } @@ -65,11 +65,11 @@ enum ValueFormatter { private static func decorated(string: String, symbol: String? = nil, signValue: Decimal? = nil) -> String { var string = string - if let symbol = symbol { + if let symbol { string = "\(string) \(symbol)" } - if let signValue = signValue { + if let signValue { var sign = "" if !signValue.isZero { sign = signValue.isSignMinus ? "-" : "+" diff --git a/UnstoppableWallet/Widget/SingleCoinPrice/SingleCoinPriceView.swift b/UnstoppableWallet/Widget/SingleCoinPrice/SingleCoinPriceView.swift index 5776926da4..61d95cd121 100644 --- a/UnstoppableWallet/Widget/SingleCoinPrice/SingleCoinPriceView.swift +++ b/UnstoppableWallet/Widget/SingleCoinPrice/SingleCoinPriceView.swift @@ -25,7 +25,7 @@ struct SingleCoinPriceView: View { } if #available(iOS 16.0, *), let chartPoints = entry.chartPoints { - let values = chartPoints.map { $0.value } + let values = chartPoints.map(\.value) if let firstValue = values.first, let lastValue = values.last, let minValue = values.min(), let maxValue = values.max() { Chart {