From 8bc1c3ae2d5f34fee27d0c432e8fedf0e5ecdd53 Mon Sep 17 00:00:00 2001 From: EA Date: Fri, 14 Jun 2024 15:37:09 +0600 Subject: [PATCH] Migrate CoinInvestors module into SwiftUI --- .../project.pbxproj | 42 ++--- .../Coin/Analytics/CoinAnalyticsView.swift | 2 - .../CoinInvestors/CoinInvestorsModule.swift | 22 --- .../CoinInvestors/CoinInvestorsService.swift | 47 ------ .../CoinInvestorsViewController.swift | 146 ------------------ .../CoinInvestorsViewModel.swift | 93 ----------- .../Coin/Investors/CoinInvestorsView.swift | 82 ++++++++++ .../Investors/CoinInvestorsViewModel.swift | 61 ++++++++ 8 files changed, 158 insertions(+), 337 deletions(-) delete mode 100644 UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift delete mode 100644 UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift delete mode 100644 UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift delete mode 100644 UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift create mode 100644 UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsView.swift create mode 100644 UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsViewModel.swift diff --git a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj index 74d8fcc459..8e9f36e7ce 100644 --- a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj +++ b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj @@ -59,7 +59,7 @@ 11B3507F2690EB4A67271333 /* CexWithdrawConfirmService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A36FFDA63E9668F1B24 /* CexWithdrawConfirmService.swift */; }; 11B35082449BDCDAF7CECC3E /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35196B818E6069195BAF1 /* KeychainManager.swift */; }; 11B35083FB285F6692754E9B /* BiometryType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359A35AEB7964A94AFFC0 /* BiometryType.swift */; }; - 11B35085F61E874613B2B882 /* CoinInvestorsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewController.swift */; }; + 11B35085F61E874613B2B882 /* CoinInvestorsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewModel.swift */; }; 11B350860CB79E9C5F032166 /* ManageAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355949F6D268EF1977DC9 /* ManageAccountViewModel.swift */; }; 11B3508846C7EB6EDC26E52C /* ManageAccountsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350911E00460DA8925165 /* ManageAccountsService.swift */; }; 11B3508877059D245C78131E /* EvmKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E9873D262F88015F120 /* EvmKit.swift */; }; @@ -148,7 +148,7 @@ 11B3517F94025A2390B8FF15 /* EvmNetworkModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35471A187C4F02BCFBFB9 /* EvmNetworkModule.swift */; }; 11B35180EBCC01488C99C660 /* TermsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353010933750F8F920E1E /* TermsViewModel.swift */; }; 11B35183F103B22537F9F9DF /* ManageWalletsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3550ED151B4C6824B9779 /* ManageWalletsViewModel.swift */; }; - 11B351856787DD75A41861B6 /* CoinInvestorsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewController.swift */; }; + 11B351856787DD75A41861B6 /* CoinInvestorsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewModel.swift */; }; 11B3518578A4531274D73A21 /* UnlinkWatchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35592753D3F2A9CCA5809 /* UnlinkWatchViewController.swift */; }; 11B35189844EFD9E4B58269D /* PageDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351FDDBEF227E161F6A0E /* PageDescription.swift */; }; 11B3518B594ECB199242C5CB /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352E52084020190C21D8C /* InputView.swift */; }; @@ -178,7 +178,6 @@ 11B351E31777084419C3B2C0 /* CreateAccountModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358145A0D9F93ACBC0301 /* CreateAccountModule.swift */; }; 11B351E4BD2180A5D6D59F23 /* PoolGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357F4747A6B256C31EC7C /* PoolGroup.swift */; }; 11B351E6C8EF6B22C5F8B98D /* NftCollectionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3529499CD211CC5A21CA2 /* NftCollectionService.swift */; }; - 11B351EE1B16B2A26B5D6A40 /* CoinInvestorsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EC8B737D03ECC70CA80 /* CoinInvestorsService.swift */; }; 11B351F04B82B33855E2CEBB /* EvmNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352EB0986D26399B7F89B /* EvmNetworkService.swift */; }; 11B351F1347A73080BB2795F /* TokenTransactionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DB5445B83B51C69D7AE /* TokenTransactionsService.swift */; }; 11B351F2BE118946AD633035 /* BlockchainTokensService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35219C4AB26DC0D104E30 /* BlockchainTokensService.swift */; }; @@ -523,7 +522,6 @@ 11B355EBC83D70F2D41D9217 /* WalletViewItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3570624266AA63F869105 /* WalletViewItemFactory.swift */; }; 11B355EC1ED6673F7F3E196C /* SendEvmService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3540BDD94203AFD41C6C7 /* SendEvmService.swift */; }; 11B355EE18C23669D470BBB0 /* NftCollectionOverviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351436E090F4C05243103 /* NftCollectionOverviewViewModel.swift */; }; - 11B355EE734C8CAC81BA1BF9 /* CoinInvestorsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EA2F51B9257D036D3E6 /* CoinInvestorsModule.swift */; }; 11B355F11DDA5EC8082C43DF /* BinanceWithdrawHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3576C0D8464F74D44EE92 /* BinanceWithdrawHandler.swift */; }; 11B355F32686B8689B4EC105 /* WalletConnectRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CD5EBBB403D46BDEF0B /* WalletConnectRequest.swift */; }; 11B355FAD0E7823AF5F8EC83 /* SendEvmTransactionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C7F043B6C41E53D43BC /* SendEvmTransactionService.swift */; }; @@ -783,7 +781,6 @@ 11B358D1687049E5DACEBC96 /* AppManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352884D47E0B23DCF2C2C /* AppManager.swift */; }; 11B358D35D2270FD78C6EF82 /* AutoLockPeriod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E41142BD3D2FF59BAE7 /* AutoLockPeriod.swift */; }; 11B358D519ACFE88A7823C7E /* ApiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3531363949F235A210921 /* ApiProvider.swift */; }; - 11B358D913A404C1DA7D4E0E /* CoinInvestorsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35FF539B93A4C61AD1D00 /* CoinInvestorsViewModel.swift */; }; 11B358D91C9D8102C46B97ED /* TransactionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B9BA734A13A0ADC507E /* TransactionsViewModel.swift */; }; 11B358DC6827FC6035BF3225 /* TokenQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353684493AFDF3711DF2B /* TokenQuery.swift */; }; 11B358DC90F3372DB98BD4A5 /* CexDepositNetworkSelectViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DDED1BC5B541DB6B4B3 /* CexDepositNetworkSelectViewModel.swift */; }; @@ -803,7 +800,6 @@ 11B3590E40C88ADD16DEEABB /* BackupMnemonicWordCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35736BA15E54066036D54 /* BackupMnemonicWordCell.swift */; }; 11B359131D838F3191A8C520 /* BtcBlockchainSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358830357DB1F87FCA006 /* BtcBlockchainSettingsViewModel.swift */; }; 11B35916211F5D5EA0DBD207 /* CoinPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3529DC8E74672659515B8 /* CoinPageViewModel.swift */; }; - 11B3591854D77701EB7218BC /* CoinInvestorsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35FF539B93A4C61AD1D00 /* CoinInvestorsViewModel.swift */; }; 11B3591C77EE71054BF819D0 /* SetPasscodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A10404D5E085E482CC7 /* SetPasscodeView.swift */; }; 11B3591DF0CC1D367C1241AF /* ExtendedKeyModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351F1248EDA20F7141AB8 /* ExtendedKeyModule.swift */; }; 11B3591E867F4E701F5458F9 /* TransactionFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3567314F1A1DF8D1B2910 /* TransactionFilterView.swift */; }; @@ -1026,7 +1022,6 @@ 11B35B7ABF2BE45FAE0461A5 /* CreateAccountAdvancedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35399E91DA7AAF4104C8F /* CreateAccountAdvancedViewController.swift */; }; 11B35B7D8E3DA75CFD13E1FF /* ReservoirNftProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CC832C2C96FA9E7B60B /* ReservoirNftProvider.swift */; }; 11B35B81B3C6EDC01D0B3C1F /* EvmNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352EB0986D26399B7F89B /* EvmNetworkService.swift */; }; - 11B35B925CE6EB25DF542611 /* CoinInvestorsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EC8B737D03ECC70CA80 /* CoinInvestorsService.swift */; }; 11B35B9351ADD99FA8919EEE /* FaqViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C09B59EF5DEB6D7EB07 /* FaqViewModel.swift */; }; 11B35B99BA314135CB139D02 /* WCSignEthereumTransactionRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BEA44ADC0D844330FB7 /* WCSignEthereumTransactionRequestViewController.swift */; }; 11B35B99C84075296D6F26DE /* UnlinkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35419B0C846238DDC50F3 /* UnlinkViewModel.swift */; }; @@ -1205,7 +1200,6 @@ 11B35DC7CD9E62F3B47ECB98 /* LogoHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359CC2E1E7853CD1547B3 /* LogoHeaderCell.swift */; }; 11B35DCAC5CAD6936EB5EB90 /* TransactionsTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3579EDE4F5BC0170FB711 /* TransactionsTableViewDataSource.swift */; }; 11B35DCCBE18D2F1F16C01C5 /* PlaceholderViewNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35FF3390A7BB8E040620D /* PlaceholderViewNew.swift */; }; - 11B35DD9C17FDD3ED40BA321 /* CoinInvestorsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EA2F51B9257D036D3E6 /* CoinInvestorsModule.swift */; }; 11B35DDB41FFB254E91B6019 /* MarkdownTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3536DB4D3D3D7771B3EA4 /* MarkdownTextCell.swift */; }; 11B35DDBD7EC98FAE5794F76 /* SecondaryButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3572105A456CCDD63E94D /* SecondaryButtonStyle.swift */; }; 11B35DDD77B56489D1EB72C5 /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3569F2E6BD5E9CBCFCA1F /* Token.swift */; }; @@ -3075,6 +3069,8 @@ D3E1E8682C1C3ACF00E07052 /* CoinReportsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E1E8662C1C3ACF00E07052 /* CoinReportsView.swift */; }; D3E1E86A2C1C3AD600E07052 /* CoinReportsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E1E8692C1C3AD600E07052 /* CoinReportsViewModel.swift */; }; D3E1E86B2C1C3AD600E07052 /* CoinReportsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E1E8692C1C3AD600E07052 /* CoinReportsViewModel.swift */; }; + D3E1E86D2C1C40D800E07052 /* CoinInvestorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E1E86C2C1C40D800E07052 /* CoinInvestorsView.swift */; }; + D3E1E86E2C1C40D800E07052 /* CoinInvestorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E1E86C2C1C40D800E07052 /* CoinInvestorsView.swift */; }; D3E323C82AE7B8E400F73914 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = D3E323C72AE7B8E400F73914 /* KeychainAccess */; }; D3E323CA2AE7B8F400F73914 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = D3E323C92AE7B8F400F73914 /* KeychainAccess */; }; D3F7D6412A94D53500477BB1 /* BaseTransactionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B106BD8E4DBD67B7700 /* BaseTransactionsService.swift */; }; @@ -3618,7 +3614,7 @@ 11B359FE71F5DE6AAD2BA3D8 /* NftMetadataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftMetadataManager.swift; sourceTree = ""; }; 11B359FF2DB6F840D867FD2F /* BottomSheetModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomSheetModule.swift; sourceTree = ""; }; 11B35A05B93CB243B6404C4A /* WelcomeTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTextView.swift; sourceTree = ""; }; - 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinInvestorsViewController.swift; sourceTree = ""; }; + 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinInvestorsViewModel.swift; sourceTree = ""; }; 11B35A10404D5E085E482CC7 /* SetPasscodeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetPasscodeView.swift; sourceTree = ""; }; 11B35A1AE56A94BEB52AC4D1 /* StorageMigrator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageMigrator.swift; sourceTree = ""; }; 11B35A1C200EC15159154E3F /* ShortcutInputCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutInputCell.swift; sourceTree = ""; }; @@ -3824,12 +3820,10 @@ 11B35E9873D262F88015F120 /* EvmKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvmKit.swift; sourceTree = ""; }; 11B35E9B9C7A88B7584507DF /* AccountRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountRecord.swift; sourceTree = ""; }; 11B35E9E1D262629CD843F7E /* ManageAccountModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManageAccountModule.swift; sourceTree = ""; }; - 11B35EA2F51B9257D036D3E6 /* CoinInvestorsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinInvestorsModule.swift; sourceTree = ""; }; 11B35EB9BA551F2F1AF7739D /* TermsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TermsManager.swift; sourceTree = ""; }; 11B35EBD933DD3C9E72F1CA8 /* EnabledWallet_v_0_25.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnabledWallet_v_0_25.swift; sourceTree = ""; }; 11B35EC03BB5316524050518 /* CexWithdrawNetworkRaw.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexWithdrawNetworkRaw.swift; sourceTree = ""; }; 11B35EC5CADBD290DDD3DE1C /* GuideCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GuideCell.swift; sourceTree = ""; }; - 11B35EC8B737D03ECC70CA80 /* CoinInvestorsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinInvestorsService.swift; sourceTree = ""; }; 11B35EC9E0E936067225C787 /* PoolSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PoolSource.swift; sourceTree = ""; }; 11B35ECB140E2565C55165A0 /* SendTonFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendTonFactory.swift; sourceTree = ""; }; 11B35ECC6866F29A33129F06 /* NftHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftHeaderView.swift; sourceTree = ""; }; @@ -3874,7 +3868,6 @@ 11B35FEC3027F45085959FBB /* NftDoubleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftDoubleCell.swift; sourceTree = ""; }; 11B35FF02BBEDAEF446D0610 /* ModuleUnlockView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModuleUnlockView.swift; sourceTree = ""; }; 11B35FF3390A7BB8E040620D /* PlaceholderViewNew.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderViewNew.swift; sourceTree = ""; }; - 11B35FF539B93A4C61AD1D00 /* CoinInvestorsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinInvestorsViewModel.swift; sourceTree = ""; }; 1A56404C1C16B85434117DB7 /* AppStatusModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStatusModule.swift; sourceTree = ""; }; 1A5640528EFD15137E218EA3 /* MainSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainSettingsViewModel.swift; sourceTree = ""; }; 1A5641572B6E46E18B52A6A9 /* SecuritySettingsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecuritySettingsModule.swift; sourceTree = ""; }; @@ -4687,6 +4680,7 @@ D3E1E8632C1C0EF400E07052 /* CoinHoldersChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinHoldersChart.swift; sourceTree = ""; }; D3E1E8662C1C3ACF00E07052 /* CoinReportsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinReportsView.swift; sourceTree = ""; }; D3E1E8692C1C3AD600E07052 /* CoinReportsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinReportsViewModel.swift; sourceTree = ""; }; + D3E1E86C2C1C40D800E07052 /* CoinInvestorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinInvestorsView.swift; sourceTree = ""; }; D3F9B0242BE38AF1009FFA95 /* RegularSendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegularSendView.swift; sourceTree = ""; }; D3F9B02A2BE3A9A1009FFA95 /* MultiSwapSendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiSwapSendView.swift; sourceTree = ""; }; D3F9B0302BE3B39D009FFA95 /* EvmDecoration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EvmDecoration.swift; sourceTree = ""; }; @@ -4837,15 +4831,13 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 11B35043F81AA7646DFDDBBC /* CoinInvestors */ = { + 11B35043F81AA7646DFDDBBC /* Investors */ = { isa = PBXGroup; children = ( - 11B35EA2F51B9257D036D3E6 /* CoinInvestorsModule.swift */, - 11B35EC8B737D03ECC70CA80 /* CoinInvestorsService.swift */, - 11B35FF539B93A4C61AD1D00 /* CoinInvestorsViewModel.swift */, - 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewController.swift */, + 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewModel.swift */, + D3E1E86C2C1C40D800E07052 /* CoinInvestorsView.swift */, ); - path = CoinInvestors; + path = Investors; sourceTree = ""; }; 11B350A2E7EE706CB00F6E34 /* BackupVerifyWords */ = { @@ -7246,7 +7238,7 @@ 11B354D11B72A988BA1D8F59 /* Markets */, 11B35C53664AC4D47BE3EDCA /* Analytics */, 58AAA82D45A42CAF49D4B60A /* CoinChart */, - 11B35043F81AA7646DFDDBBC /* CoinInvestors */, + 11B35043F81AA7646DFDDBBC /* Investors */, 11B35F5F70D13CDD22955832 /* Treasuries */, 11B35B9A31858F53A2490110 /* MajorHolders */, 11B350D0C95CBAF2B4327C4F /* Audits */, @@ -9185,6 +9177,7 @@ D35B518B21942E7A00504FBA /* TermsViewController.swift in Sources */, D04D98EB268055A2001A3135 /* TransactionRecord.swift in Sources */, D36DE0FD272FD92F000BC916 /* SwapSelectProviderService.swift in Sources */, + D3E1E86E2C1C40D800E07052 /* CoinInvestorsView.swift in Sources */, D008CA67267C8E1800001E0A /* ApproveTransactionRecord.swift in Sources */, D09D768F2A2E06D6004311E6 /* SendTronConfirmationViewController.swift in Sources */, D0A690262BFCB51800E59296 /* TronPresendHandler.swift in Sources */, @@ -9493,9 +9486,7 @@ 58AAABED534A95A11B332D44 /* CoinChartViewModel.swift in Sources */, D3833B002BF335D100ACECFB /* MarketNewsViewModel.swift in Sources */, 58AAAA71882CB345D56BBA00 /* CoinChartFactory.swift in Sources */, - 11B35DD9C17FDD3ED40BA321 /* CoinInvestorsModule.swift in Sources */, - 11B358D913A404C1DA7D4E0E /* CoinInvestorsViewModel.swift in Sources */, - 11B351856787DD75A41861B6 /* CoinInvestorsViewController.swift in Sources */, + 11B351856787DD75A41861B6 /* CoinInvestorsViewModel.swift in Sources */, 11B3507F17791BC895872490 /* BrandFooterView.swift in Sources */, 6BCD53152A161F4800993F20 /* BackupViewModel.swift in Sources */, 11B35D10A6A15EFA47FCE6D0 /* TextCell.swift in Sources */, @@ -9714,7 +9705,6 @@ D07157DC2A2DD968006F141F /* SendTronModule.swift in Sources */, 11B35A82532EC55909EFBAD8 /* LaunchScreen.swift in Sources */, 6BB14F762C01D04200E879B2 /* CheckBoxUiView.swift in Sources */, - 11B35B925CE6EB25DF542611 /* CoinInvestorsService.swift in Sources */, 6BCD53052A161F4100993F20 /* ICloudBackupTermsViewController.swift in Sources */, 11B354FA6F6BF59F64560590 /* CoinTreasuriesViewModel.swift in Sources */, 11B35F6092E0950714E277E4 /* PostCell.swift in Sources */, @@ -10640,6 +10630,7 @@ D008CA5E267C8DEC00001E0A /* EvmOutgoingTransactionRecord.swift in Sources */, D35B518C21942E7A00504FBA /* TermsViewController.swift in Sources */, D04D98EA268055A2001A3135 /* TransactionRecord.swift in Sources */, + D3E1E86D2C1C40D800E07052 /* CoinInvestorsView.swift in Sources */, D008CA66267C8E1800001E0A /* ApproveTransactionRecord.swift in Sources */, D384066E21831B3D007D50AD /* LaunchService.swift in Sources */, D0A690252BFCB51800E59296 /* TronPresendHandler.swift in Sources */, @@ -10950,9 +10941,7 @@ D3833AFF2BF335D100ACECFB /* MarketNewsViewModel.swift in Sources */, D36DE0D8272FD887000BC916 /* OneInchDataSource.swift in Sources */, 58AAA2EBAFC1C443C48BA857 /* CoinChartFactory.swift in Sources */, - 11B355EE734C8CAC81BA1BF9 /* CoinInvestorsModule.swift in Sources */, - 11B3591854D77701EB7218BC /* CoinInvestorsViewModel.swift in Sources */, - 11B35085F61E874613B2B882 /* CoinInvestorsViewController.swift in Sources */, + 11B35085F61E874613B2B882 /* CoinInvestorsViewModel.swift in Sources */, 6BCD53142A161F4800993F20 /* BackupViewModel.swift in Sources */, 11B35D7420EF4FB9C4DDF0B9 /* BrandFooterView.swift in Sources */, 6BCD53002A161F4100993F20 /* BackupCloudModule.swift in Sources */, @@ -11174,7 +11163,6 @@ 11B3551E5E9A6D167F7BA078 /* LaunchScreenManager.swift in Sources */, 11B35FA6F9EE876BD65E9AD6 /* LaunchScreen.swift in Sources */, D07157DB2A2DD968006F141F /* SendTronModule.swift in Sources */, - 11B351EE1B16B2A26B5D6A40 /* CoinInvestorsService.swift in Sources */, 6B2907272AF0CB8A006157D6 /* WidgetCoinAppShowModule.swift in Sources */, D0532CC42B149E450015DF40 /* WatchService.swift in Sources */, 6BCD53042A161F4100993F20 /* ICloudBackupTermsViewController.swift in Sources */, diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsView.swift index aa3ee3d1ba..3229fa4690 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsView.swift @@ -555,8 +555,6 @@ struct CoinAnalyticsView: View { value: investors ) { CoinInvestorsView(coinUid: viewModel.coin.uid) - .navigationTitle("coin_analytics.funding".localized) - .ignoresSafeArea() } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift deleted file mode 100644 index a90e40324f..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsModule.swift +++ /dev/null @@ -1,22 +0,0 @@ -import SwiftUI -import UIKit - -enum 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)) - } -} - -struct CoinInvestorsView: UIViewControllerRepresentable { - typealias UIViewControllerType = UIViewController - - let coinUid: String - - func makeUIViewController(context _: Context) -> UIViewController { - CoinInvestorsModule.viewController(coinUid: coinUid) - } - - func updateUIViewController(_: UIViewController, context _: Context) {} -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift deleted file mode 100644 index e92bfa9b1b..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsService.swift +++ /dev/null @@ -1,47 +0,0 @@ -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class CoinInvestorsService { - private let coinUid: String - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private var tasks = Set() - - @PostPublished private(set) var state: DataStatus<[CoinInvestment]> = .loading - - init(coinUid: String, marketKit: MarketKit.Kit, currencyManager: CurrencyManager) { - self.coinUid = coinUid - self.marketKit = marketKit - self.currencyManager = currencyManager - - sync() - } - - private func sync() { - tasks = Set() - - state = .loading - - Task { [weak self, marketKit, coinUid] in - do { - let investments = try await marketKit.investments(coinUid: coinUid) - self?.state = .completed(investments) - } catch { - self?.state = .failed(error) - } - }.store(in: &tasks) - } -} - -extension CoinInvestorsService { - var usdCurrency: Currency { - let currencies = currencyManager.currencies - return currencies.first { $0.code == "USD" } ?? currencies[0] - } - - func refresh() { - sync() - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift deleted file mode 100644 index 1fc7b4f4fc..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewController.swift +++ /dev/null @@ -1,146 +0,0 @@ -import ComponentKit -import Foundation -import HUD -import RxCocoa -import RxSwift -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class CoinInvestorsViewController: ThemeViewController { - private let viewModel: CoinInvestorsViewModel - private let urlManager: UrlManager - private let disposeBag = DisposeBag() - - private let tableView = SectionsTableView(style: .grouped) - private let spinner = HUDActivityView.create(with: .medium24) - private let errorView = PlaceholderViewModule.reachabilityView() - - private var viewItems: [CoinInvestorsViewModel.ViewItem]? - - init(viewModel: CoinInvestorsViewModel, urlManager: UrlManager) { - self.viewModel = viewModel - self.urlManager = urlManager - - super.init() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - title = "coin_analytics.funding".localized - - view.addSubview(tableView) - tableView.snp.makeConstraints { maker in - maker.edges.equalToSuperview() - } - - tableView.sectionDataSource = self - - tableView.separatorStyle = .none - tableView.backgroundColor = .clear - - view.addSubview(spinner) - spinner.snp.makeConstraints { maker in - maker.center.equalToSuperview() - } - - spinner.startAnimating() - - view.addSubview(errorView) - errorView.snp.makeConstraints { maker in - maker.edges.equalTo(view.safeAreaLayoutGuide) - } - - errorView.configureSyncError(action: { [weak self] in self?.onRetry() }) - - subscribe(disposeBag, viewModel.viewItemsDriver) { [weak self] in self?.sync(viewItems: $0) } - subscribe(disposeBag, viewModel.loadingDriver) { [weak self] loading in - self?.spinner.isHidden = !loading - } - subscribe(disposeBag, viewModel.syncErrorDriver) { [weak self] visible in - self?.errorView.isHidden = !visible - } - } - - @objc private func onRetry() { - viewModel.onTapRetry() - } - - private func sync(viewItems: [CoinInvestorsViewModel.ViewItem]?) { - self.viewItems = viewItems - - if viewItems != nil { - tableView.bounces = true - } else { - tableView.bounces = false - } - - 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 - ), - ] - ) - } - - 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) - } - ) - } - - 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) - } - ) - } - - func buildSections() -> [SectionProtocol] { - guard let viewItems else { - return [] - } - - var sections = [SectionProtocol]() - - for (index, viewItem) in viewItems.enumerated() { - sections.append(headerSection(index: index, title: viewItem.amount, value: viewItem.info)) - sections.append(section(index: index, fundViewItems: viewItem.fundViewItems, isLast: index == viewItems.count - 1)) - } - - return sections - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift deleted file mode 100644 index 13fef8ed77..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinInvestors/CoinInvestorsViewModel.swift +++ /dev/null @@ -1,93 +0,0 @@ -import Combine -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -class CoinInvestorsViewModel { - private let service: CoinInvestorsService - private var cancellables = Set() - - private let viewItemsRelay = BehaviorRelay<[ViewItem]?>(value: nil) - private let loadingRelay = BehaviorRelay(value: false) - private let syncErrorRelay = BehaviorRelay(value: false) - - init(service: CoinInvestorsService) { - self.service = service - - service.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - sync(state: service.state) - } - - private func sync(state: DataStatus<[CoinInvestment]>) { - switch state { - case .loading: - viewItemsRelay.accept(nil) - loadingRelay.accept(true) - syncErrorRelay.accept(false) - case let .completed(investments): - viewItemsRelay.accept(investments.map { viewItem(investment: $0) }) - loadingRelay.accept(false) - syncErrorRelay.accept(false) - case .failed: - viewItemsRelay.accept(nil) - loadingRelay.accept(false) - syncErrorRelay.accept(true) - } - } - - 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) } - ) - } - - private func fundViewItem(fund: CoinInvestment.Fund) -> FundViewItem { - FundViewItem( - uid: fund.uid, - name: fund.name, - logoUrl: fund.logoUrl, - isLead: fund.isLead, - url: fund.website - ) - } -} - -extension CoinInvestorsViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { - viewItemsRelay.asDriver() - } - - var loadingDriver: Driver { - loadingRelay.asDriver() - } - - var syncErrorDriver: Driver { - syncErrorRelay.asDriver() - } - - func onTapRetry() { - service.refresh() - } -} - -extension CoinInvestorsViewModel { - struct ViewItem { - let amount: String - let info: String - let fundViewItems: [FundViewItem] - } - - struct FundViewItem { - let uid: String - let name: String - let logoUrl: String - let isLead: Bool - let url: String - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsView.swift new file mode 100644 index 0000000000..7815e8e6c3 --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsView.swift @@ -0,0 +1,82 @@ +import Kingfisher +import MarketKit +import SwiftUI + +struct CoinInvestorsView: View { + @StateObject var viewModel: CoinInvestorsViewModel + + init(coinUid: String) { + _viewModel = StateObject(wrappedValue: CoinInvestorsViewModel(coinUid: coinUid)) + } + + var body: some View { + ThemeView { + switch viewModel.state { + case .loading: + ProgressView() + case let .loaded(investments): + list(investments: investments) + case .failed: + SyncErrorView { + viewModel.onRetry() + } + } + } + .navigationTitle("coin_analytics.funding".localized) + .navigationBarTitleDisplayMode(.inline) + } + + @ViewBuilder private func list(investments: [CoinInvestment]) -> some View { + ScrollView { + LazyVStack(spacing: .margin24) { + ForEach(investments.indices, id: \.self) { index in + let investment = investments[index] + + VStack(spacing: .margin12) { + VStack(spacing: 0) { + HorizontalDivider() + + HStack(spacing: .margin8) { + Text(investment.amount.flatMap { ValueFormatter.instance.formatShort(currency: viewModel.usdCurrency, value: $0) } ?? "---").textBody(color: .themeJacob) + Spacer() + Text("\(investment.round) - \(DateHelper.instance.formatFullDateOnly(from: investment.date))").textSubhead1(color: .themeLeah) + } + .padding(.horizontal, .margin16) + .padding(.vertical, .margin12) + } + + ListSection { + ForEach(investment.funds.indices, id: \.self) { index in + let fund = investment.funds[index] + + ClickableRow(spacing: .margin8) { + UrlManager.open(url: fund.website) + } content: { + HStack(spacing: .margin16) { + KFImage.url(URL(string: fund.logoUrl)) + .resizable() + .placeholder { RoundedRectangle(cornerRadius: .cornerRadius8).fill(Color.themeSteel20) } + .clipShape(RoundedRectangle(cornerRadius: .cornerRadius8)) + .frame(width: .iconSize32, height: .iconSize32) + + Text(fund.name).textBody() + } + + Spacer() + + if fund.isLead { + Text("coin_analytics.funding.lead".localized).textSubhead1(color: .themeRemus) + } + + Image.disclosureIcon + } + } + } + .padding(.horizontal, .margin16) + } + } + } + .padding(EdgeInsets(top: .margin12, leading: 0, bottom: .margin32, trailing: 0)) + } + } +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsViewModel.swift new file mode 100644 index 0000000000..aad73d3316 --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Investors/CoinInvestorsViewModel.swift @@ -0,0 +1,61 @@ +import Combine +import Foundation +import HsExtensions +import MarketKit + +class CoinInvestorsViewModel: ObservableObject { + private let coinUid: String + private let marketKit = App.shared.marketKit + private let currencyManager = App.shared.currencyManager + private var tasks = Set() + + @Published private(set) var state: State = .loading + + init(coinUid: String) { + self.coinUid = coinUid + + sync() + } + + private func sync() { + tasks = Set() + + if case .failed = state { + state = .loading + } + + Task { [weak self, marketKit, coinUid] in + do { + let investments = try await marketKit.investments(coinUid: coinUid) + + await MainActor.run { [weak self] in + self?.state = .loaded(investments: investments) + } + } catch { + await MainActor.run { [weak self] in + self?.state = .failed + } + } + } + .store(in: &tasks) + } +} + +extension CoinInvestorsViewModel { + var usdCurrency: Currency { + let currencies = currencyManager.currencies + return currencies.first { $0.code == "USD" } ?? currencies[0] + } + + func onRetry() { + sync() + } +} + +extension CoinInvestorsViewModel { + enum State { + case loading + case loaded(investments: [CoinInvestment]) + case failed + } +}