diff --git a/Podfile b/Podfile index 143ae28b1c..dacadc3509 100644 --- a/Podfile +++ b/Podfile @@ -26,6 +26,9 @@ abstract_target 'fearlessAll' do pod 'keccak.c' pod 'Charts', '~> 4.1.0' pod 'XNetworking', :podspec => 'https://raw.githubusercontent.com/soramitsu/x-networking/0.0.37/AppCommonNetworking/XNetworking/XNetworking.podspec' + pod 'SoraUIKit', :git => 'https://github.com/soramitsu/ios-ui.git', :tag => '1.0.2' + pod 'IdensicMobileSDK', :http => 'https://github.com/PayWings/PayWingsOnboardingKycSDK-iOS-IdensicMobile/archive/v2.2.1.tar.gz' + pod 'SCard', :git => 'https://github.com/sora-xor/sora-card-ios', :branch => 'release/1.1.0' def pods_with_configurations if %r{^true$}i.match ENV['F_DEV'] @@ -40,10 +43,10 @@ abstract_target 'fearlessAll' do pod 'SSFLogger' pod 'SSFRuntimeCodingService' pod 'SSFStorageQueryKit' - pod 'SSFChainConnection' + pod 'SSFChainConnection', '0.1.4' pod 'SSFNetwork' pod 'SSFUtils' - pod 'SSFChainRegistry' + pod 'SSFChainRegistry', '0.1.4' pod 'SSFHelpers', '0.1.2' pod 'SSFCloudStorage' end diff --git a/Podfile.lock b/Podfile.lock index d57f25fa99..cfc3f96ef9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -10,9 +10,9 @@ PODS: - Charts/Core (= 4.1.0) - Charts/Core (4.1.0): - SwiftAlgorithms (~> 1.0) - - CocoaLumberjack (3.8.0): - - CocoaLumberjack/Core (= 3.8.0) - - CocoaLumberjack/Core (3.8.0) + - CocoaLumberjack (3.8.1): + - CocoaLumberjack/Core (= 3.8.1) + - CocoaLumberjack/Core (3.8.1) - CommonWallet/Core (1.16.0): - RobinHood (~> 2.6.1) - SoraFoundation/DateProcessing (~> 1.0.0) @@ -23,6 +23,7 @@ PODS: - Cuckoo (1.10.3): - Cuckoo/Swift (= 1.10.3) - Cuckoo/Swift (1.10.3) + - eIDRTC (1.1.34) - FireMock (3.1) - GoogleAPIClientForREST/Core (1.2.1): - GTMSessionFetcher (>= 1.1.7) @@ -41,6 +42,7 @@ PODS: - GTMSessionFetcher/Core (3.1.1) - GTMSessionFetcher/Full (3.1.1): - GTMSessionFetcher/Core + - IdensicMobileSDK (1.25.0) - IrohaCrypto (0.10.0): - IrohaCrypto/BIP39 (= 0.10.0) - IrohaCrypto/blake2 (= 0.10.0) @@ -70,12 +72,22 @@ PODS: - IrohaCrypto/blake2 - IrohaCrypto/Common - keccak.c (0.1.3) - - Kingfisher (7.7.0) + - Kingfisher (7.9.1) + - PayWingsOAuthSDK (1.2.2) + - PayWingsOnboardingKYC (5.1.13): + - VideoID (= 7.1.31) - R.swift (6.1.0): - R.swift.Library (~> 5.3.0) - R.swift.Library (5.3.0) - ReachabilitySwift (5.0.0) - RobinHood (2.6.7) + - SCard (1.1.0): + - IdensicMobileSDK + - PayWingsOAuthSDK (= 1.2.2) + - PayWingsOnboardingKYC (= 5.1.13) + - R.swift (~> 6.1.0) + - SnapKit + - SoraUIKit (~> 1.0.1) - scrypt.c (0.1.1) - secp256k1.c (0.1.2) - SnapKit (5.0.1) @@ -130,12 +142,13 @@ PODS: - SoraUI/PinView (1.10.3): - SoraUI/Controls - SoraUI/Skrull (1.10.3) + - SoraUIKit (1.0.2) - Sourcery (1.9.2): - Sourcery/CLI-Only (= 1.9.2) - Sourcery/CLI-Only (1.9.2) - - SSFChainConnection (0.1.0): + - SSFChainConnection (0.1.4): - SSFUtils - - SSFChainRegistry (0.1.0): + - SSFChainRegistry (0.1.4): - RobinHood - SSFChainConnection - SSFLogger @@ -143,14 +156,14 @@ PODS: - SSFNetwork - SSFRuntimeCodingService - SSFUtils - - SSFCloudStorage (0.1.6): + - SSFCloudStorage (0.1.15): - GoogleAPIClientForREST/Drive (~> 1.2.1) - GoogleSignIn (~> 7.0.0) - IrohaCrypto/Scrypt - SSFModels - SSFUtils - TweetNacl (~> 1.0.0) - - SSFCrypto (0.1.0): + - SSFCrypto (0.1.11): - IrohaCrypto/ed25519 - IrohaCrypto/Scrypt - IrohaCrypto/secp256k1 @@ -201,7 +214,7 @@ PODS: - SSFCrypto - SSFRuntimeCodingService - SSFUtils - - SSFUtils (0.1.13): + - SSFUtils (0.1.14): - BigInt (~> 5.0) - IrohaCrypto/ed25519 - IrohaCrypto/Scrypt @@ -214,7 +227,7 @@ PODS: - Starscream - TweetNacl (~> 1.0.0) - xxHash-Swift (~> 1.0.0) - - SSFXCM (0.1.2): + - SSFXCM (0.1.13): - IrohaCrypto - RobinHood - SSFChainConnection @@ -232,9 +245,11 @@ PODS: - CocoaLumberjack (~> 3.0) - SwiftAlgorithms (1.0.0) - SwiftFormat/CLI (0.47.13) - - SwiftLint (0.52.2) + - SwiftLint (0.52.4) - SwiftyBeaver (1.9.5) - TweetNacl (1.0.2) + - VideoID (7.1.31): + - eIDRTC (= 1.1.34) - XNetworking (0.0.37) - xxHash-Swift (1.0.13) @@ -243,19 +258,22 @@ DEPENDENCIES: - CommonWallet/Core - Cuckoo - FireMock + - "IdensicMobileSDK (from `{:http=>\"https://github.com/PayWings/PayWingsOnboardingKycSDK-iOS-IdensicMobile/archive/v2.2.1.tar.gz\"}`)" - IrohaCrypto - keccak.c - Kingfisher - R.swift (= 6.1.0) - ReachabilitySwift - RobinHood (~> 2.6.7) + - SCard (from `https://github.com/sora-xor/sora-card-ios`, branch `release/1.1.0`) - SnapKit (~> 5.0.0) - SoraFoundation (~> 1.0.0) - SoraKeystore (from `https://github.com/soramitsu/keystore-iOS.git`, tag `1.0.1`) - SoraUI (~> 1.10.3) + - SoraUIKit (from `https://github.com/soramitsu/ios-ui.git`, tag `1.0.2`) - Sourcery (~> 1.4) - - SSFChainConnection - - SSFChainRegistry + - SSFChainConnection (= 0.1.4) + - SSFChainRegistry (= 0.1.4) - SSFCloudStorage - SSFCrypto - SSFEraKit @@ -277,13 +295,14 @@ DEPENDENCIES: - XNetworking (from `https://raw.githubusercontent.com/soramitsu/x-networking/0.0.37/AppCommonNetworking/XNetworking/XNetworking.podspec`) SPEC REPOS: - https://github.com/cocoapods/Specs.git: + https://github.com/CocoaPods/Specs.git: - AppAuth - BigInt - Charts - CocoaLumberjack - CommonWallet - Cuckoo + - eIDRTC - FireMock - GoogleAPIClientForREST - GoogleSignIn @@ -292,6 +311,8 @@ SPEC REPOS: - IrohaCrypto - keccak.c - Kingfisher + - PayWingsOAuthSDK + - PayWingsOnboardingKYC - R.swift - R.swift.Library - ReachabilitySwift @@ -308,6 +329,7 @@ SPEC REPOS: - SwiftLint - SwiftyBeaver - TweetNacl + - VideoID - xxHash-Swift https://github.com/soramitsu/SSFSpecs.git: - SSFChainConnection @@ -327,9 +349,17 @@ SPEC REPOS: - SSFXCM EXTERNAL SOURCES: + IdensicMobileSDK: + :http: https://github.com/PayWings/PayWingsOnboardingKycSDK-iOS-IdensicMobile/archive/v2.2.1.tar.gz + SCard: + :branch: release/1.1.0 + :git: https://github.com/sora-xor/sora-card-ios SoraKeystore: :git: https://github.com/soramitsu/keystore-iOS.git :tag: 1.0.1 + SoraUIKit: + :git: https://github.com/soramitsu/ios-ui.git + :tag: 1.0.2 Starscream: :git: https://github.com/soramitsu/fearless-starscream.git :tag: 4.0.8 @@ -337,9 +367,17 @@ EXTERNAL SOURCES: :podspec: https://raw.githubusercontent.com/soramitsu/x-networking/0.0.37/AppCommonNetworking/XNetworking/XNetworking.podspec CHECKOUT OPTIONS: + IdensicMobileSDK: + :http: https://github.com/PayWings/PayWingsOnboardingKycSDK-iOS-IdensicMobile/archive/v2.2.1.tar.gz + SCard: + :commit: 2e2e63188a1967673da9503f5a503d91e68ed44f + :git: https://github.com/sora-xor/sora-card-ios SoraKeystore: :git: https://github.com/soramitsu/keystore-iOS.git :tag: 1.0.1 + SoraUIKit: + :git: https://github.com/soramitsu/ios-ui.git + :tag: 1.0.2 Starscream: :git: https://github.com/soramitsu/fearless-starscream.git :tag: 4.0.8 @@ -348,32 +386,38 @@ SPEC CHECKSUMS: AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 BigInt: f668a80089607f521586bbe29513d708491ef2f7 Charts: ce0768268078eee0336f122c3c4ca248e4e204c5 - CocoaLumberjack: 78abfb691154e2a9df8ded4350d504ee19d90732 + CocoaLumberjack: 5c7e64cdb877770859bddec4d3d5a0d7c9299df9 CommonWallet: 3c67d5fd85593a20f6b55777c2660ff886fc4148 Cuckoo: 930598bd4ae95860c658b3eea30903d946ebef36 + eIDRTC: debca63e4c367be509c77292df65b9527d695f10 FireMock: 3eed872059c12f94855413347da83b9d6d1a6fac GoogleAPIClientForREST: a8b95a252014ce2e618df6b75dc72eca2c00b4af GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842 GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72 + IdensicMobileSDK: 724b75dbb204a9c1ae1dafe5c1366b8aeb00b6cf IrohaCrypto: eb3772088068d8938198205b62b0a9dc5b8ce005 keccak.c: 859583afdaccb4e4fcc0f0096064d101580313f4 - Kingfisher: f043ac666dfc96c1f37604f93effb45a7ee3a3e1 + Kingfisher: 1d14e9f59cbe19389f591c929000332bf70efd32 + PayWingsOAuthSDK: 97c104c6efa982313fd515c22339279f24ac3461 + PayWingsOnboardingKYC: abff20d772e9b87e9315b4999feb7401d6557eee R.swift: ec98ff71c4ab2f6fd01dd077e5afd15e63a4834c R.swift.Library: 0fc583cb55a99e28901299cc451614cad1161962 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 RobinHood: 40edb5db53d5763433af25f95d81f7860d7acdc6 + SCard: 0f3a1fe782ac1624c92f57df4c029e35c3f8c15b scrypt.c: b42ae06183251329d2b2c620c226fb541a4a3592 secp256k1.c: db47b726585d80f027423682eb369729e61b3b20 SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb SoraFoundation: 988d90ee3159311b02e42aeba0cf7e85d8bc724c SoraKeystore: e1789fe41412606d8a1116b86bd00d46d4cb9ccb SoraUI: 1ec71151eb962591eeb898bcdd98bded59745f2d + SoraUIKit: 258aa43f318cb306b29cdadb52139d794c184333 Sourcery: 179539341c2261068528cd15a31837b7238fd901 - SSFChainConnection: a232b35cc083e9e9e79ff6ed228812cddd11ace6 - SSFChainRegistry: bb26ac38e4c43aeaf29f1a959603aa5fd6889d7e - SSFCloudStorage: 5124491f345bdd304b4d07c6d2368dfde59bc61d - SSFCrypto: 1d82ecd49dc44d47e155bdecd7b873348f5bdd16 + SSFChainConnection: 760f0bbe0d711cc0f184b951dea9e840a2962346 + SSFChainRegistry: adfcfa6f8e7dae4730e258989c2a58ee674bf1e1 + SSFCloudStorage: 37fbba3ad3e93a637d9c1a9b85910f4fa29596de + SSFCrypto: 0d1b79e1d253055189ec42b6155d045f464ab993 SSFEraKit: a6f2a8bdefcdfa3ad8ff8f48b242000ea50744cd SSFExtrinsicKit: f5ab32700622894d2e7a5fca254a3f659d3a6a9f SSFHelpers: 93becab69ebcef78bceee530fd2d57939d21052c @@ -383,18 +427,19 @@ SPEC CHECKSUMS: SSFRuntimeCodingService: d67154d18789604a448b4e9f1c261ade291629e8 SSFSigner: 2ff97e574d16a5e0d87afc6f50177c5ad14c38bf SSFStorageQueryKit: 3063fdf0a84c9b7c1c2a2a08b862162bd0d38694 - SSFUtils: 8fd131123804c122c031763a8436d45e1ac373c2 - SSFXCM: 59cb429a5c20c4f34f6c383e36ab8644922703b0 + SSFUtils: 3254af5db8930b8c4bdaa94d9e3a51596afafc79 + SSFXCM: 2e8458396a85185631b8003619b9873583b67e10 Starscream: b676ee89781677a2d8d36029a78c970710e2d3eb SVGKit: 1ad7513f8c74d9652f94ed64ddecda1a23864dea SwiftAlgorithms: 38dda4731d19027fdeee1125f973111bf3386b53 SwiftFormat: 73573b89257437c550b03d934889725fbf8f75e5 - SwiftLint: 1ac76dac888ca05cb0cf24d0c85887ec1209961d + SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3 SwiftyBeaver: 84069991dd5dca07d7069100985badaca7f0ce82 TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 + VideoID: d48d4f30f79f12229421a09e65692561960dc5b5 XNetworking: 516d982bd74ff208222381d27e07052a5d897aaf xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: 5b8590914b2dd1916d27ab986de50d4cb62f69f6 +PODFILE CHECKSUM: 03a8123d6101eb62952610b9d962188917fe9a09 COCOAPODS: 1.11.3 diff --git a/fearless.xcodeproj/project.pbxproj b/fearless.xcodeproj/project.pbxproj index 236063d6ad..2b681cee67 100644 --- a/fearless.xcodeproj/project.pbxproj +++ b/fearless.xcodeproj/project.pbxproj @@ -1709,6 +1709,8 @@ C6CA3081286192C50087776D /* DelegationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CA3080286192C50087776D /* DelegationViewModel.swift */; }; C6D7CE0927E83A9F00FFAA6B /* AccountImportViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D7CE0827E83A9F00FFAA6B /* AccountImportViewLayout.swift */; }; C6D7CE0B27E9932D00FFAA6B /* AccountImportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D7CE0A27E9932D00FFAA6B /* AccountImportViewController.swift */; }; + C6D9B91F2AA826470061C1F7 /* SoraCardInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D9B91E2AA826470061C1F7 /* SoraCardInitializer.swift */; }; + C6D9B9212AA8941C0061C1F7 /* ResetSoraCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D9B9202AA8941C0061C1F7 /* ResetSoraCard.swift */; }; C6E5671768DA68535DA5B1C7 /* ControllerAccountConfirmationViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F02DBCA4A63A5E52E3739374 /* ControllerAccountConfirmationViewFactory.swift */; }; C6FB932E27C9334100563E61 /* AvailableExportOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6FB932D27C9334100563E61 /* AvailableExportOptionsProvider.swift */; }; C77CCA7FF969A2F006A0B6C4 /* WalletChainAccountDashboardProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E1C5E0E16867BDA51B6734 /* WalletChainAccountDashboardProtocols.swift */; }; @@ -4408,6 +4410,8 @@ C6D50DB62A958FD00040573D /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = ""; }; C6D7CE0827E83A9F00FFAA6B /* AccountImportViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountImportViewLayout.swift; sourceTree = ""; }; C6D7CE0A27E9932D00FFAA6B /* AccountImportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountImportViewController.swift; sourceTree = ""; }; + C6D9B91E2AA826470061C1F7 /* SoraCardInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoraCardInitializer.swift; sourceTree = ""; }; + C6D9B9202AA8941C0061C1F7 /* ResetSoraCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetSoraCard.swift; sourceTree = ""; }; C6F8BBBA9EABA266B288333F /* AnalyticsValidatorsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsValidatorsViewFactory.swift; sourceTree = ""; }; C6FB932D27C9334100563E61 /* AvailableExportOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableExportOptionsProvider.swift; sourceTree = ""; }; C705CA1083C1EE58426D90CD /* AllDoneInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AllDoneInteractor.swift; sourceTree = ""; }; @@ -9621,6 +9625,7 @@ FA5AE96327B1326400B2564E /* ChainsUpdatedEvent.swift */, 07089AF428B64701001566CA /* ChainReconnectingEvent.swift */, FA37AE4C28603C37001DCA96 /* StakingUpdatedEvent.swift */, + C6D9B9202AA8941C0061C1F7 /* ResetSoraCard.swift */, ); path = Events; sourceTree = ""; @@ -12090,6 +12095,7 @@ FA38C9A32760700B005C5577 /* Services */ = { isa = PBXGroup; children = ( + C6D9B91E2AA826470061C1F7 /* SoraCardInitializer.swift */, 073417AE298BA28300104F41 /* Equilibrium */, 0713097B28C6387B002B17D0 /* ScamService */, FA99426E2805524200D771E5 /* GetBalanceProvider */, @@ -14883,6 +14889,7 @@ 8490145824A9406D008F705E /* LegalData.swift in Sources */, 8472C601265D7A1F00E2481B /* WebSocketProviderSource.swift in Sources */, FA004899282CCFCD0032FF49 /* SelectValidatorsStartParachainViewModelFactory.swift in Sources */, + C6D9B9212AA8941C0061C1F7 /* ResetSoraCard.swift in Sources */, 8425EA9025EA7E5800C307C9 /* ElectedValidatorInfo.swift in Sources */, 846AF8442525BE0100868F37 /* Price.swift in Sources */, 84CD357325264F640081BC0B /* WalletTotalPriceViewModel.swift in Sources */, @@ -15085,6 +15092,7 @@ FAA0136828DA12E3000A5230 /* StakingRedeemConfirmationViewModel.swift in Sources */, 849ABE6D2627949E00011A2A /* BatchMapper.swift in Sources */, FAFFAE7E29AC84B10074AF1F /* SubqueryDelegatorHistoryData.swift in Sources */, + C6D9B91F2AA826470061C1F7 /* SoraCardInitializer.swift in Sources */, FAE5F62F27B2383E00F13206 /* AddCustomNodeViewState.swift in Sources */, FAFFAE4029AC84850074AF1F /* AccountManagementPresentable.swift in Sources */, FA15BC152823CB7B0037C023 /* ParachainCollatorOperationFactory.swift in Sources */, diff --git a/fearless/ApplicationLayer/Services/SoraCardInitializer.swift b/fearless/ApplicationLayer/Services/SoraCardInitializer.swift new file mode 100644 index 0000000000..30ed53aeff --- /dev/null +++ b/fearless/ApplicationLayer/Services/SoraCardInitializer.swift @@ -0,0 +1,97 @@ +import SCard +import SoraFoundation +import RobinHood +import SSFModels +import SoraUIKit + +final class SoraCardInitializer { + private let wallet: MetaAccountModel + private let soraChainAsset: ChainAsset + private let accountInfoSubscriptionAdapter: AccountInfoSubscriptionAdapter + var onSwapHandler: ((UIViewController) -> Void)? + + init( + wallet: MetaAccountModel, + soraChainAsset: ChainAsset, + accountInfoSubscriptionAdapter: AccountInfoSubscriptionAdapter + ) { + self.wallet = wallet + self.soraChainAsset = soraChainAsset + self.accountInfoSubscriptionAdapter = accountInfoSubscriptionAdapter + } + + func initSoraCard() -> SCard { + guard SCard.shared == nil else { return SCard.shared! } + + let addressProvider: () -> String = { [weak self] in + guard let strongSelf = self, + let accountId = strongSelf.wallet.fetch(for: strongSelf.soraChainAsset.chain.accountRequest())?.accountId else { return "" } + + let address = try? AddressFactory.address( + for: accountId, + chain: strongSelf.soraChainAsset.chain + ) + return address ?? "" + } + + let xorBalanceStream = SCStream(wrappedValue: Decimal(0)) + + let soraCard = SCard( + addressProvider: addressProvider, + config: .local, + balanceStream: xorBalanceStream, + onSwapController: { [weak self] vc in + self?.onSwapHandler?(vc) + } + ) + + SCard.shared = soraCard + + LocalizationManager.shared.addObserver(with: soraCard) { [weak soraCard] _, newLocalization in + soraCard?.selectedLocalization = newLocalization + } + + return soraCard + } +} + +extension SCard.Config { + static let prod = SCard.Config( + backendUrl: SoraCardCIKeys.backendProdUrl, + pwAuthDomain: SoraCardCIKeys.domainProd, + pwApiKey: SoraCardCIKeys.apiKeyProd, + kycUrl: SoraCardCIKeys.kycEndpointUrlProd, + kycUsername: SoraCardCIKeys.kycUsernameProd, + kycPassword: SoraCardCIKeys.kycPasswordProd, + xOneEndpoint: SoraCardCIKeys.xOneEndpointProd, + xOneId: SoraCardCIKeys.xOneIdProd, + environmentType: .prod, + themeMode: SoramitsuUI.shared.themeMode + ) + + static let test = SCard.Config( + backendUrl: SoraCardCIKeys.backendTestUrl, + pwAuthDomain: SoraCardCIKeys.domainTest, + pwApiKey: SoraCardCIKeys.apiKeyTest, + kycUrl: SoraCardCIKeys.kycEndpointUrlTest, + kycUsername: SoraCardCIKeys.kycUsernameTest, + kycPassword: SoraCardCIKeys.kycPasswordTest, + xOneEndpoint: SoraCardCIKeys.xOneEndpointTest, + xOneId: SoraCardCIKeys.xOneIdTest, + environmentType: .test, + themeMode: SoramitsuUI.shared.themeMode + ) + + static let local = SCard.Config( + backendUrl: "https://backend.dev.sora-card.tachi.soramitsu.co.jp/", + pwAuthDomain: "soracard.com", + pwApiKey: "6974528a-ee11-4509-b549-a8d02c1aec0d", + kycUrl: "https://kyc-test.soracard.com/mobile", + kycUsername: "E7A6CB83-630E-4D24-88C5-18AAF96032A4", + kycPassword: "75A55B7E-A18F-4498-9092-58C7D6BDB333", + xOneEndpoint: "https://dev.x1ex.com/widgets/sdk.js", + xOneId: "sprkwdgt-WYL6QBNC", + environmentType: .test, + themeMode: SoramitsuUI.shared.themeMode + ) +} diff --git a/fearless/CIKeys.stencil b/fearless/CIKeys.stencil index d67f6aebd0..60a1cbf4ce 100644 --- a/fearless/CIKeys.stencil +++ b/fearless/CIKeys.stencil @@ -13,6 +13,23 @@ enum SoraCardCIKeys { static var endpoint: String = "{{ argument.soraCardKycEndpoint }}" static var username: String = "{{ argument.soraCardKycUsername }}" static var password: String = "{{ argument.soraCardKycPassword }}" + + static var backendTestUrl: String = "{{ argument.soraCardBackendTestUrl }}" + static var backendProdUrl: String = "{{ argument.soraCardBackendProdUrl }}" + static var apiKeyTest: String = "{{ argument.soraCardAPIKeyTest }}" + static var apiKeyProd: String = "{{ argument.soraCardAPIKeyProd }}" + static var domainTest: String = "{{ argument.soraCardDomainTest }}" + static var domainProd: String = "{{ argument.soraCardDomainProd }}" + static var kycEndpointUrlTest: String = "{{ argument.soraCardKYCEndpointUrlTest }}" + static var kycEndpointUrlProd: String = "{{ argument.soraCardKYCEndpointUrlProd }}" + static var kycUsernameTest: String = "{{ argument.soraCardKycUsernameTest }}" + static var kycUsernameProd: String = "{{ argument.soraCardKycUsernameProd }}" + static var kycPasswordTest: String = "{{ argument.soraCardKycPasswordTest }}" + static var kycPasswordProd: String = "{{ argument.soraCardKycPasswordProd }}" + static var xOneEndpointTest: String = "{{ argument.soraCardXOneEndpointTest }}" + static var xOneEndpointProd: String = "{{ argument.soraCardXOneEndpointProd }}" + static var xOneIdTest: String = "{{ argument.soraCardXOneIdTest }}" + static var xOneIdProd: String = "{{ argument.soraCardXOneIdProd }}" } enum PayWingsCIKeys { diff --git a/fearless/Common/EventCenter/EventVisitor.swift b/fearless/Common/EventCenter/EventVisitor.swift index 2a85d2b298..236c346b66 100644 --- a/fearless/Common/EventCenter/EventVisitor.swift +++ b/fearless/Common/EventCenter/EventVisitor.swift @@ -26,6 +26,8 @@ protocol EventVisitorProtocol: AnyObject { func processStakingUpdatedEvent() func processZeroBalancesSettingChanged() func processRemoteSubscriptionWasUpdated(event: WalletRemoteSubscriptionWasUpdatedEvent) + + func processResetSoraCard() } extension EventVisitorProtocol { @@ -54,4 +56,6 @@ extension EventVisitorProtocol { func processStakingUpdatedEvent() {} func processZeroBalancesSettingChanged() {} func processRemoteSubscriptionWasUpdated(event _: WalletRemoteSubscriptionWasUpdatedEvent) {} + + func processResetSoraCard() {} } diff --git a/fearless/Common/EventCenter/Events/ResetSoraCard.swift b/fearless/Common/EventCenter/Events/ResetSoraCard.swift new file mode 100644 index 0000000000..b2b3213927 --- /dev/null +++ b/fearless/Common/EventCenter/Events/ResetSoraCard.swift @@ -0,0 +1,15 @@ +// +// ResetSoraCard.swift +// fearless +// +// Created by Денис Лебедько on 06.09.2023. +// Copyright © 2023 Soramitsu. All rights reserved. +// + +import Foundation + +struct ResetSoraCard: EventProtocol { + func accept(visitor: EventVisitorProtocol) { + visitor.processResetSoraCard() + } +} diff --git a/fearless/Common/Helpers/ChainAssetsFetching.swift b/fearless/Common/Helpers/ChainAssetsFetching.swift index 42106464fc..ae674a0348 100644 --- a/fearless/Common/Helpers/ChainAssetsFetching.swift +++ b/fearless/Common/Helpers/ChainAssetsFetching.swift @@ -91,7 +91,7 @@ final class ChainAssetsFetching: ChainAssetFetchingProtocol { sortDescriptors: [SortDescriptor], completionBlock: @escaping (Result<[ChainAsset], Error>?) -> Void ) { - let operation = chainRepository.fetchAllOperation(with: .none) + let operation = chainRepository.fetchAllOperation(with: RepositoryFetchOptions()) operation.completionBlock = { [weak self] in guard let strongSelf = self else { return diff --git a/fearless/Common/Substrate/CallFactory/Updates/SubstrateCallFactoryV9430.swift b/fearless/Common/Substrate/CallFactory/Updates/SubstrateCallFactoryV9430.swift index e33802328f..d77422bf49 100644 --- a/fearless/Common/Substrate/CallFactory/Updates/SubstrateCallFactoryV9430.swift +++ b/fearless/Common/Substrate/CallFactory/Updates/SubstrateCallFactoryV9430.swift @@ -11,10 +11,10 @@ class SubstrateCallFactoryV9430: SubstrateCallFactoryV9420 { callName: path.callName ) } - + override func bond( amount: BigUInt, - controller: String, + controller _: String, rewardDestination: RewardDestination, chainAsset: ChainAsset ) throws -> any RuntimeCallable { diff --git a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListAssembly.swift b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListAssembly.swift index 33c861ce0d..7daabe940b 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListAssembly.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListAssembly.swift @@ -33,6 +33,13 @@ final class ChainAssetListAssembly { let dependencyContainer = ChainAssetListDependencyContainer() + let router = ChainAssetListRouter() + + let accountInfoSubscriptionAdapter = AccountInfoSubscriptionAdapter( + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + selectedMetaAccount: wallet + ) + let interactor = ChainAssetListInteractor( wallet: wallet, priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, @@ -43,7 +50,7 @@ final class ChainAssetListAssembly { accountInfoFetching: accountInfoFetching, dependencyContainer: dependencyContainer ) - let router = ChainAssetListRouter() + let viewModelFactory = ChainAssetListViewModelFactory( assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), settings: SettingsManager.shared diff --git a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListInteractor.swift b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListInteractor.swift index b2b555f2fc..33eecb205a 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListInteractor.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListInteractor.swift @@ -2,6 +2,7 @@ import UIKit import RobinHood import SoraKeystore import SSFModels +import SCard final class ChainAssetListInteractor { // MARK: - Private properties @@ -173,6 +174,38 @@ extension ChainAssetListInteractor: ChainAssetListInteractorInput { let updatedAccount = wallet.replacingAssetsFilterOptions(filterOptions) save(updatedAccount) } + + func initSoraCard(completionBlock: @escaping (Result?) -> Void) { + if let soraCard = SCard.shared { + completionBlock(.success(soraCard)) + } + let dependencies = dependencyContainer.buildDependencies(for: wallet) + let chainAssetFetching = dependencies.chainAssetFetching + let accountInfoSubscriptionAdapter = dependencies.accountInfoSubscriptionAdapter + chainAssetFetching.fetch(filters: [.assetName("xor")], sortDescriptors: []) { [weak self] result in + guard let strongSelf = self else { return } + switch result { + case let .success(chainAssets): + if let soraChainAsset = chainAssets.first(where: { chainAsset in + chainAsset.chain.chainId == Chain.soraMain.genesisHash + }) { + DispatchQueue.main.async { + let soraCardInitializer = SoraCardInitializer( + wallet: strongSelf.wallet, + soraChainAsset: soraChainAsset, + accountInfoSubscriptionAdapter: accountInfoSubscriptionAdapter + ) + let soraCard = soraCardInitializer.initSoraCard() + completionBlock(.success(soraCard)) + } + } + default: + DispatchQueue.main.async { + completionBlock(nil) + } + } + } + } } private extension ChainAssetListInteractor { @@ -297,6 +330,10 @@ extension ChainAssetListInteractor: EventVisitorProtocol { output?.handleWalletChanged(wallet: wallet) updateChainAssets(using: filters, sorts: sorts) } + + func processResetSoraCard() { + output?.didReceiveResetSoraCard() + } } extension ChainAssetListInteractor: ChainsIssuesCenterListener { diff --git a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListPresenter.swift b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListPresenter.swift index 753e557297..eef3d9bbc3 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListPresenter.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListPresenter.swift @@ -1,6 +1,7 @@ import Foundation import SoraFoundation import SSFModels +import SCard enum AssetListDisplayType { case chain @@ -57,6 +58,36 @@ final class ChainAssetListPresenter { let accountInfosCopy = self.accountInfos let prices = self.prices let chainsWithMissingAccounts = self.chainsWithMissingAccounts + let onClose: () -> Void = { [weak self] in + SCard.shared?.isSCBannerHidden = true + self?.view?.setSoraCard(isHidden: true) + } + let onCard: () -> Void = { [weak self] in + self?.router.startSoraCard(from: self?.view) + } + + guard let soraCard = SCard.shared else { + interactor.initSoraCard { result in + var soraCardService: SCard? + if case let .success(soraCard) = result { + soraCardService = soraCard + } + let viewModel = self.viewModelFactory.buildViewModel( + wallet: self.wallet, + chainAssets: chainAssets, + locale: self.selectedLocale, + accountInfos: accountInfosCopy, + prices: prices, + chainsWithMissingAccounts: chainsWithMissingAccounts, + activeFilters: self.activeFilters, + soraCardService: soraCardService, + onClose: onClose, + onCard: onCard + ) + self.view?.didReceive(viewModel: viewModel) + } + return + } let viewModel = self.viewModelFactory.buildViewModel( wallet: self.wallet, @@ -65,7 +96,10 @@ final class ChainAssetListPresenter { accountInfos: accountInfosCopy, prices: prices, chainsWithMissingAccounts: chainsWithMissingAccounts, - activeFilters: self.activeFilters + activeFilters: self.activeFilters, + soraCardService: soraCard, + onClose: onClose, + onCard: onCard ) DispatchQueue.main.async { @@ -272,6 +306,10 @@ extension ChainAssetListPresenter: ChainAssetListInteractorOutput { } provideViewModel() } + + func didReceiveResetSoraCard() { + view?.setSoraCard(isHidden: false) + } } // MARK: - Localizable diff --git a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListProtocols.swift b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListProtocols.swift index 62f5d93148..9fde56e5fb 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListProtocols.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListProtocols.swift @@ -1,11 +1,13 @@ import Foundation import SSFModels +import SCard typealias ChainAssetListModuleCreationResult = (view: ChainAssetListViewInput, input: ChainAssetListModuleInput) protocol ChainAssetListViewInput: ControllerBackedProtocol { func didReceive(viewModel: ChainAssetListViewModel) func reloadBanners() + func setSoraCard(isHidden: Bool) } protocol ChainAssetListViewOutput: AnyObject { @@ -16,6 +18,7 @@ protocol ChainAssetListViewOutput: AnyObject { } protocol ChainAssetListInteractorInput: AnyObject { + func initSoraCard(completionBlock: @escaping (Result?) -> Void) func setup(with output: ChainAssetListInteractorOutput) func updateChainAssets( using filters: [ChainAssetsFetching.Filter], @@ -36,6 +39,7 @@ protocol ChainAssetListInteractorOutput: AnyObject { func updateViewModel(isInitSearchState: Bool) func didReceive(accountInfosByChainAssets: [ChainAsset: AccountInfo?]) func handleWalletChanged(wallet: MetaAccountModel) + func didReceiveResetSoraCard() } protocol ChainAssetListRouterInput: @@ -71,6 +75,14 @@ protocol ChainAssetListRouterInput: uniqueChainModel: UniqueChainModel, from view: ControllerBackedProtocol? ) + func showPolkaswap( + controller: UIViewController, + from view: ControllerBackedProtocol? + ) + + func startSoraCard( + from view: ControllerBackedProtocol? + ) } protocol ChainAssetListModuleInput: AnyObject { diff --git a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListRouter.swift b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListRouter.swift index 60e4133faf..f5223cf486 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListRouter.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListRouter.swift @@ -1,5 +1,6 @@ import Foundation import SSFModels +import SCard final class ChainAssetListRouter: ChainAssetListRouterInput { func showChainAccount( @@ -103,4 +104,18 @@ final class ChainAssetListRouter: ChainAssetListRouterInput { view?.controller.present(navigationController, animated: true) } + + func showPolkaswap(controller: UIViewController, from view: ControllerBackedProtocol?) { + let navigationController = FearlessNavigationController(rootViewController: controller) + + view?.controller.navigationController?.present( + navigationController, + animated: true + ) + } + + func startSoraCard(from view: ControllerBackedProtocol?) { + guard let vc = view?.controller else { return } + SCard.shared?.start(in: vc) + } } diff --git a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewController.swift b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewController.swift index af803b1d74..e7aaba2afc 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewController.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewController.swift @@ -2,6 +2,7 @@ import UIKit import SoraFoundation import SnapKit import SoraUI +import SCard enum HiddenSectionState { case hidden @@ -87,6 +88,7 @@ final class ChainAssetListViewController: private extension ChainAssetListViewController { func configureTableView() { + rootView.tableView.registerClassForCell(SCCardCell.self) rootView.tableView.registerClassForCell(ChainAccountBalanceTableCell.self) rootView.tableView.delegate = self rootView.tableView.dataSource = self @@ -132,6 +134,13 @@ private extension ChainAssetListViewController { // MARK: - ChainAssetListViewInput extension ChainAssetListViewController: ChainAssetListViewInput { + func setSoraCard(isHidden: Bool) { + rootView.setSoraCard(isHidden: isHidden) + rootView.tableView.beginUpdates() + rootView.tableView.setAndLayoutTableHeaderView(header: rootView.headerViewContainer) + rootView.tableView.endUpdates() + } + func reloadBanners() { guard viewModel != nil else { return @@ -149,6 +158,9 @@ extension ChainAssetListViewController: ChainAssetListViewInput { self.viewModel = viewModel hiddenSectionState = viewModel.hiddenSectionState + if let soraItem = viewModel.soraCardItem { + rootView.bindSoraCard(item: soraItem, isHidden: viewModel.soraCardHidden) + } if isInitialReload { rootView.tableView.reloadData() diff --git a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewLayout.swift b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewLayout.swift index 293ea65d19..5bab5414e7 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewLayout.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ChainAssetListViewLayout.swift @@ -1,4 +1,5 @@ import UIKit +import SCard import SoraUI import SnapKit @@ -20,6 +21,7 @@ final class ChainAssetListViewLayout: UIView { var keyboardAdoptableConstraint: Constraint? weak var bannersView: UIView? + private var soraCardCell: SCCardCell? var headerViewContainer: UIStackView = { UIFactory.default.createVerticalStackView(spacing: UIConstants.bigOffset) @@ -52,6 +54,23 @@ final class ChainAssetListViewLayout: UIView { } } + func bindSoraCard(item: SCCardItem, isHidden: Bool) { + let cell = SCCardCell() + cell.set(item: item, context: nil) + if soraCardCell == nil { + soraCardCell = cell + soraCardCell?.contentView.isHidden = isHidden + headerViewContainer.addArrangedSubview(soraCardCell!.contentView) + soraCardCell?.contentView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview() + } + } + } + + func setSoraCard(isHidden: Bool) { + soraCardCell?.contentView.isHidden = isHidden + } + private func setupLayout() { tableView.tableHeaderView = headerViewContainer headerViewContainer.snp.makeConstraints { make in diff --git a/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModel.swift b/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModel.swift index 1a6ac36297..183bf578be 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModel.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModel.swift @@ -1,3 +1,5 @@ +import SCard + enum ChainAssetListTableSection: Int { case active case hidden @@ -10,4 +12,6 @@ struct ChainAssetListViewModel { let hiddenSectionState: HiddenSectionState let emptyStateIsActive: Bool let bannerIsHidden: Bool + let soraCardItem: SCCardItem? + let soraCardHidden: Bool } diff --git a/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModelFactory.swift b/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModelFactory.swift index 75199f9dea..3d82a6b104 100644 --- a/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModelFactory.swift +++ b/fearless/Modules/NewWallet/ChainAssetList/ViewModel/ChainAssetListViewModelFactory.swift @@ -3,6 +3,8 @@ import SoraFoundation import SoraKeystore import BigInt import SSFModels +import SCard +import SoraUIKit // swiftlint:disable function_parameter_count function_body_length protocol ChainAssetListViewModelFactoryProtocol { @@ -13,7 +15,10 @@ protocol ChainAssetListViewModelFactoryProtocol { accountInfos: [ChainAssetKey: AccountInfo?], prices: PriceDataUpdated, chainsWithMissingAccounts: [ChainModel.Id], - activeFilters: [ChainAssetsFetching.Filter] + activeFilters: [ChainAssetsFetching.Filter], + soraCardService: SCard?, + onClose: (() -> Void)?, + onCard: (() -> Void)? ) -> ChainAssetListViewModel } @@ -43,8 +48,20 @@ final class ChainAssetListViewModelFactory: ChainAssetListViewModelFactoryProtoc accountInfos: [ChainAssetKey: AccountInfo?], prices: PriceDataUpdated, chainsWithMissingAccounts: [ChainModel.Id], - activeFilters: [ChainAssetsFetching.Filter] + activeFilters: [ChainAssetsFetching.Filter], + soraCardService: SCard?, + onClose: (() -> Void)?, + onCard: (() -> Void)? ) -> ChainAssetListViewModel { + var soraCardItem: SCCardItem? + if let service = soraCardService { + soraCardItem = SCCardItem( + service: service, + onClose: onClose, + onCard: onCard + ) + } + var fiatBalanceByChainAsset: [ChainAsset: Decimal] = [:] chainAssets.forEach { chainAsset in @@ -162,7 +179,9 @@ final class ChainAssetListViewModelFactory: ChainAssetListViewModelFactoryProtoc isColdBoot: isColdBoot, hiddenSectionState: hiddenSectionState, emptyStateIsActive: emptyStateIsActive, - bannerIsHidden: bannerIsHidden.contains(true) + bannerIsHidden: bannerIsHidden.contains(true), + soraCardItem: soraCardItem, + soraCardHidden: soraCardService?.isSCBannerHidden ?? true ) } } diff --git a/fearless/Modules/Profile/ProfilePresenter.swift b/fearless/Modules/Profile/ProfilePresenter.swift index 6ee793b79e..1496169757 100644 --- a/fearless/Modules/Profile/ProfilePresenter.swift +++ b/fearless/Modules/Profile/ProfilePresenter.swift @@ -1,6 +1,7 @@ import Foundation import SoraFoundation import SoraKeystore +import SCard final class ProfilePresenter { private weak var view: ProfileViewProtocol? @@ -76,6 +77,8 @@ extension ProfilePresenter: ProfilePresenterProtocol { switch option { case .accountList: wireframe.showAccountSelection(from: view, moduleOutput: self) + case .soraCard: + wireframe.startSoraCard(from: view) case .changePincode: wireframe.showPincodeChange(from: view) case .language: @@ -91,6 +94,9 @@ extension ProfilePresenter: ProfilePresenterProtocol { break case .zeroBalances: break + case .resetSoraCard: + SCard.shared?.isSCBannerHidden = false + eventCenter.notify(with: ResetSoraCard()) } } diff --git a/fearless/Modules/Profile/ProfileProtocol.swift b/fearless/Modules/Profile/ProfileProtocol.swift index c9668b678b..05e501c2f3 100644 --- a/fearless/Modules/Profile/ProfileProtocol.swift +++ b/fearless/Modules/Profile/ProfileProtocol.swift @@ -53,6 +53,7 @@ protocol ProfileWireframeProtocol: ErrorPresentable, func showSelectCurrency(from view: ProfileViewProtocol?, with: MetaAccountModel) func close(view: ControllerBackedProtocol?) func showPolkaswapDisclaimer(from view: ControllerBackedProtocol?) + func startSoraCard(from view: ControllerBackedProtocol?) } protocol ProfileViewFactoryProtocol: AnyObject { diff --git a/fearless/Modules/Profile/ProfileWireframe.swift b/fearless/Modules/Profile/ProfileWireframe.swift index 16dc8e6b51..1a19862ce5 100644 --- a/fearless/Modules/Profile/ProfileWireframe.swift +++ b/fearless/Modules/Profile/ProfileWireframe.swift @@ -1,5 +1,6 @@ import Foundation import UIKit +import SCard final class ProfileWireframe: ProfileWireframeProtocol, AuthorizationPresentable { lazy var rootAnimator: RootControllerAnimationCoordinatorProtocol = RootControllerAnimationCoordinator() @@ -118,4 +119,9 @@ final class ProfileWireframe: ProfileWireframeProtocol, AuthorizationPresentable animated: true ) } + + func startSoraCard(from view: ControllerBackedProtocol?) { + guard let vc = view?.controller else { return } + SCard.shared?.start(in: vc) + } } diff --git a/fearless/Modules/Profile/ViewModel/ProfileViewModelFactory.swift b/fearless/Modules/Profile/ViewModel/ProfileViewModelFactory.swift index ec0f620502..a7e5401a65 100644 --- a/fearless/Modules/Profile/ViewModel/ProfileViewModelFactory.swift +++ b/fearless/Modules/Profile/ViewModel/ProfileViewModelFactory.swift @@ -18,6 +18,7 @@ protocol ProfileViewModelFactoryProtocol: AnyObject { enum ProfileOption: UInt, CaseIterable { case accountList + case soraCard case currency case language case polkaswapDisclaimer @@ -25,6 +26,7 @@ enum ProfileOption: UInt, CaseIterable { case biometry case about case zeroBalances + case resetSoraCard } final class ProfileViewModelFactory: ProfileViewModelFactoryProtocol { @@ -127,6 +129,8 @@ final class ProfileViewModelFactory: ProfileViewModelFactoryProtocol { for: locale, missingEthAccount: missingAccountIssue.isNotEmpty ) + case .soraCard: + return createSoraCardViewModel(for: locale) case .changePincode: return createChangePincode(for: locale) case .language: @@ -141,6 +145,8 @@ final class ProfileViewModelFactory: ProfileViewModelFactoryProtocol { return createCurrencyViewModel(from: currency, locale: locale) case .zeroBalances: return createZeroBalancesViewModel(for: locale, wallet: wallet) + case .resetSoraCard: + return createResetSoraCard() } } @@ -286,6 +292,32 @@ final class ProfileViewModelFactory: ProfileViewModelFactoryProtocol { return viewModel } + private func createSoraCardViewModel(for locale: Locale) -> ProfileOptionViewModel { + let title = R.string.localizable.profileSoracardTitle(preferredLanguages: locale.rLanguages) + let viewModel = ProfileOptionViewModel( + title: title, + icon: R.image.iconSoraCard()!, + accessoryTitle: nil, + accessoryImage: nil, + accessoryType: .arrow, + option: .soraCard + ) + return viewModel + } + + private func createResetSoraCard() -> ProfileOptionViewModel { + let title = "Get back this lovely banner" + let viewModel = ProfileOptionViewModel( + title: title, + icon: R.image.iconSoraCard()!, + accessoryTitle: nil, + accessoryImage: nil, + accessoryType: .arrow, + option: .resetSoraCard + ) + return viewModel + } + private func getDayChangeAttributedString( currency: Currency, dayChange: Decimal,