diff --git a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj index bee229ce49..78951639a3 100644 --- a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj +++ b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj @@ -19,7 +19,6 @@ 11B3501D2E8C6FB3B3B767FC /* StatStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D6FC62F4797DEE1C419 /* StatStorage.swift */; }; 11B3501EA3658BFDC67DEB1F /* ThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E7E7A5DBB09A2A5197D /* ThemeView.swift */; }; 11B3502C799E4ED762F95252 /* AddEvmSyncSourceModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35504934CE3C31D523F82 /* AddEvmSyncSourceModule.swift */; }; - 11B3502DA4A2B869638AF4D8 /* MarketListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355BEB95969D89B3F8876 /* MarketListViewModel.swift */; }; 11B3502E567C29F297090D9B /* SyncErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3516207E568E7D54428CA /* SyncErrorView.swift */; }; 11B3502E7AA00ACFE8EE8CD9 /* FormTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35392439DBC8C06DCCB60 /* FormTextView.swift */; }; 11B35030E4C9A4157CE5FF43 /* WidgetProd.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = 11B35DDE879F1628BB2CE523 /* WidgetProd.entitlements */; }; @@ -30,7 +29,6 @@ 11B350388CD7F33B10BD3F4B /* AdapterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3583932F270503C1DF3F0 /* AdapterFactory.swift */; }; 11B3503BF015EA47E1061122 /* AccountRecordStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358556C8FC5368E14D81E /* AccountRecordStorage.swift */; }; 11B3503F5875A29E6949B13C /* EvmPrivateKeyService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D67F24A3128864A8700 /* EvmPrivateKeyService.swift */; }; - 11B3504029EB87A32DB63666 /* MarketTopService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35770F0C72E1CD3F99985 /* MarketTopService.swift */; }; 11B35040917F10257C949596 /* NftCollectionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350E6966203DF2855369A /* NftCollectionRecord.swift */; }; 11B35041FF23044B3CCDDA55 /* CoinInvestment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35264F7CE80AD5D9A540A /* CoinInvestment.swift */; }; 11B3504619330D3DB0E0ECD1 /* PublicKeysModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35111F25CE7D0C8E0B29B /* PublicKeysModule.swift */; }; @@ -104,7 +102,6 @@ 11B350ECEE8748562D27249F /* CexWithdrawNetworkSelectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351C522855F29C6B038D3 /* CexWithdrawNetworkSelectViewController.swift */; }; 11B350F12C3CA54080C16031 /* ManageWalletsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C4D645B4468F84EADB7 /* ManageWalletsViewController.swift */; }; 11B350F24818BABB6DB6512A /* SingleCoinPriceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CFAA2B156E439EB18B3 /* SingleCoinPriceView.swift */; }; - 11B350F36947CF278CDB436B /* MarketListMarketFieldDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353B060BDF272932D3522 /* MarketListMarketFieldDecorator.swift */; }; 11B350F58D6907C9A9A79F6B /* NftViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35419084A6CB11230E3C6 /* NftViewController.swift */; }; 11B350F8D2D09F1BD5ECF003 /* SendEvmViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F6B511DA5E0C60ED156 /* SendEvmViewModel.swift */; }; 11B350F9484020EFF74EFF1F /* MnemonicInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DB358405198CF67F11D /* MnemonicInputCell.swift */; }; @@ -185,11 +182,9 @@ 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 */; }; - 11B351EEC95E342C2B4F5BC4 /* MarketHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3543F4D196A47EFE3E6F7 /* MarketHeaderCell.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 */; }; - 11B351F81CCF4675CBDAC9B0 /* DropdownSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F9BA41AC15436A4B977 /* DropdownSortHeaderView.swift */; }; 11B351F991634E3E6A0846EF /* NftHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35ECC6866F29A33129F06 /* NftHeaderView.swift */; }; 11B351FB99274553725754E4 /* GuidesModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352CFEDEBF0A01CC7073D /* GuidesModule.swift */; }; 11B351FC393EDD17C3487796 /* SelectorModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353C09FE554834C760777 /* SelectorModule.swift */; }; @@ -238,8 +233,6 @@ 11B35262B98EA59CDA12DF97 /* WalletConnectSessionStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355C1E3C922BAE804AAF9 /* WalletConnectSessionStorage.swift */; }; 11B35264EC1BABABCDDD1F67 /* TonIncomingTransactionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3577A9294A3EE662872D7 /* TonIncomingTransactionRecord.swift */; }; 11B3526AA8E758606BC0CE38 /* CexWithdrawService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3548F0E1223B08D3B7F0C /* CexWithdrawService.swift */; }; - 11B3527103D25C72BC849651 /* MarketOverviewTopPairsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350465C489A233625E8F2 /* MarketOverviewTopPairsDataSource.swift */; }; - 11B352712EC6F2C7F6965443 /* MarketWatchlistViewModelOld.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3566FE007887C3528583C /* MarketWatchlistViewModelOld.swift */; }; 11B3527C3BD088DCCA6959C3 /* ModuleUnlockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35FF02BBEDAEF446D0610 /* ModuleUnlockView.swift */; }; 11B3527D20636D21F0F45C80 /* CurrentDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35779E6353B98B298FF29 /* CurrentDateProvider.swift */; }; 11B3527F2E2D46DC307E6D3D /* RestoreSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E343901BA7DE01181CB /* RestoreSettingsViewModel.swift */; }; @@ -258,7 +251,6 @@ 11B3529B3DD134BC0770BD20 /* MarkdownModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35609D3FA1729A7D80153 /* MarkdownModule.swift */; }; 11B3529CFD24A94DC35B476E /* CoinAnalyticsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358DFD25E8DC35F689D5C /* CoinAnalyticsViewModel.swift */; }; 11B3529D506ADAEB715BF0D1 /* RestorePrivateKeyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35625BCC4536F39B151F0 /* RestorePrivateKeyViewModel.swift */; }; - 11B352A7A3457BBAF4BF704F /* MarketOverviewCategoryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A0AF4D03160AF66D1D9 /* MarketOverviewCategoryService.swift */; }; 11B352AA36A25DF590166418 /* NftAddressMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BEEB24CDB82D3F4E7C0 /* NftAddressMetadata.swift */; }; 11B352AB213E0F3C147EAEE9 /* SendEvmTransactionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B31362C98B401A8F9A1 /* SendEvmTransactionViewController.swift */; }; 11B352AE20E447BA1E9E890B /* SwitchAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350BC3E707879846AC0AA /* SwitchAccountViewModel.swift */; }; @@ -274,11 +266,9 @@ 11B352CBDFAABC82F02F66E9 /* MarkdownHeader1Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D31D3EC415789CFA160 /* MarkdownHeader1Cell.swift */; }; 11B352D006136B42D2705778 /* BalanceData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BDEB703708795B71C4E /* BalanceData.swift */; }; 11B352D47A0F5A3E4AF8F948 /* BaseUniswapV3MultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351FAE6B01F29FC37B3C2 /* BaseUniswapV3MultiSwapProvider.swift */; }; - 11B352D8DDF054073BC79FC2 /* CoinRankModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358A22655004017228F65 /* CoinRankModule.swift */; }; 11B352DF096B6CFD050D500D /* CoinRecord_v19.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B2C6C103AFF4CCC6E91 /* CoinRecord_v19.swift */; }; 11B352E00B6E0DF4F6D42486 /* DashAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358CA18471A93188933B4 /* DashAdapter.swift */; }; 11B352E420B3FBCD85612E63 /* TransactionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350CCAA0C9F2F5279F680 /* TransactionsViewController.swift */; }; - 11B352E46C24498018071705 /* MarketCategoryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357229D5E717F2051F0AC /* MarketCategoryService.swift */; }; 11B352E503309454C976ED03 /* MarkdownImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3563ED22080EE222848A5 /* MarkdownImageCell.swift */; }; 11B352E613B0EC5D0DA14570 /* RestoreSelectViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DCDDACF2BB1E0748ABB /* RestoreSelectViewModel.swift */; }; 11B352E8348A715EB537F643 /* TransactionFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3544AC69419F31F20F34E /* TransactionFilterViewModel.swift */; }; @@ -305,7 +295,6 @@ 11B3531D97E44DA1D8280C35 /* EditDuressPasscodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3594CBF3EA39A848D22EB /* EditDuressPasscodeViewModel.swift */; }; 11B3531F75BB6113B49DC088 /* BarPageControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3512EF5B66B852F5E05FB /* BarPageControl.swift */; }; 11B35321C9FCFD1DFA4401A3 /* SendEvmService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3540BDD94203AFD41C6C7 /* SendEvmService.swift */; }; - 11B353260AE7B998C07955E6 /* MarketCategoryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357229D5E717F2051F0AC /* MarketCategoryService.swift */; }; 11B35328067C30C80DF244DF /* BackupVerifyWordsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3576FCFC9394BA37975FC /* BackupVerifyWordsViewModel.swift */; }; 11B35328EA42C49649B1E3F6 /* SyncMode_v_0_24.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CB98A27269A510F40EE /* SyncMode_v_0_24.swift */; }; 11B3532D03B0893AB8E46CD9 /* BalanceViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3591AD106DAC0D18FEDD7 /* BalanceViewItem.swift */; }; @@ -342,7 +331,6 @@ 11B3538FA5A4953A7C9AC9E6 /* SingleCoinPriceWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351F5E57874D4517F67B7 /* SingleCoinPriceWidget.swift */; }; 11B353917D2223D2B275429A /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359D48FD6D82735C8969A /* Error.swift */; }; 11B35394C8DD94B9C726B22B /* CexAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359198B26152903D5CA14 /* CexAccount.swift */; }; - 11B353973C1ADD51D174AC74 /* CoinRankService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3513AC6560B9C37C342F3 /* CoinRankService.swift */; }; 11B3539B3634BF7B3B1B9061 /* DescriptionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3515BDAF15B6F7EEAB609 /* DescriptionCell.swift */; }; 11B3539E833ABB2D6F696916 /* BlockchainSettingRecord_v_0_24.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3526A40F07F6C8E77BEF9 /* BlockchainSettingRecord_v_0_24.swift */; }; 11B353A07F9259765D90F3BA /* NftService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355129D9F61172FCAB8C0 /* NftService.swift */; }; @@ -354,20 +342,16 @@ 11B353BAEF83867422611E7B /* TransactionFilterModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BCF17FE0D9238AA4341 /* TransactionFilterModule.swift */; }; 11B353C149EC597A051E8310 /* BinanceWithdrawHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3576C0D8464F74D44EE92 /* BinanceWithdrawHandler.swift */; }; 11B353C7553F40CEEA28678B /* PasscodeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B5570E7513DF2A455BB /* PasscodeManager.swift */; }; - 11B353CB3021FA5266D07607 /* MarketWatchlistToggleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3562819DF141457837340 /* MarketWatchlistToggleService.swift */; }; 11B353CBE0B92639753A9591 /* FaqRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358D98E1FBA6909D352DA /* FaqRepository.swift */; }; 11B353CE5AFDEB1F3BBF73F9 /* OpenSeaNftProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C1DF4F98D814CFE3951 /* OpenSeaNftProvider.swift */; }; 11B353D3A4F2305366835086 /* NftActivityHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351EC6F1B4D72D52B4D16 /* NftActivityHeaderView.swift */; }; 11B353D4BC292465358979D3 /* ValueLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355166E437B7ADB8B8EBA /* ValueLevel.swift */; }; 11B353DE48A4B088210D927D /* CoinAnalyticsRatingScaleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35FDC67CE58FBE44A4107 /* CoinAnalyticsRatingScaleViewController.swift */; }; - 11B353E15F4A208D393C7262 /* MarketCategoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3584888F2DB8CCFAA90DF /* MarketCategoryViewController.swift */; }; - 11B353E17EA348D431520FAD /* MarketListMarketPairDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3557E5ACDC89EF79C8C0C /* MarketListMarketPairDecorator.swift */; }; 11B353E4793549B6A4F23997 /* CoinOverviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3506BFA73130CA9A1FF71 /* CoinOverviewView.swift */; }; 11B353E61A5496074178741C /* SendAvailableBalanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3526E11EC0F9CFCC69D17 /* SendAvailableBalanceViewModel.swift */; }; 11B353E7A2462E19D946E723 /* CellComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355436F62829DBE3C92B4 /* CellComponent.swift */; }; 11B353EAF32244B06E44FAD1 /* PrivateKeysViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A9DB4112F41D7FCAC12 /* PrivateKeysViewModel.swift */; }; 11B353EDF27AB81FCF2A36EE /* GuidesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352E6CB5B964E2A1521CC /* GuidesViewModel.swift */; }; - 11B353F04B500616AC5CB9C5 /* MarketTopPairsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C5CA7497C540FFC5D39 /* MarketTopPairsViewController.swift */; }; 11B353F2788F7E8F42C5E03D /* EvmPrivateKeyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352E62EBBDE01560EB2E4 /* EvmPrivateKeyViewController.swift */; }; 11B353F671EA70F8BE7F02F0 /* NftAssetTitleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353D752983424F341F2FC /* NftAssetTitleCell.swift */; }; 11B353F6BB87F0F1933D63C2 /* AddEvmSyncSourceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F8A77664848396B7567 /* AddEvmSyncSourceService.swift */; }; @@ -399,7 +383,6 @@ 11B354283B8AC609B65AADDF /* FavoriteCoinRecord_v_0_38.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E255F6CA21FFA9E6B42 /* FavoriteCoinRecord_v_0_38.swift */; }; 11B3542A74C72C4CE03C727B /* CoinToggleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A3B8FB90E561DE3F22B /* CoinToggleViewController.swift */; }; 11B35434C09F1E3818DC857B /* ReceiveDerivationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357EEC98939F9C7AA3271 /* ReceiveDerivationViewModel.swift */; }; - 11B3543546FE55AE0AB91FAF /* MarketOverviewTopPairsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352BDC42A2F717AFAE7BD /* MarketOverviewTopPairsService.swift */; }; 11B3543A420A23064B056925 /* ReceiveAddressViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3532A1DC90E3D0E3403F8 /* ReceiveAddressViewModel.swift */; }; 11B3543A7A9EB1E0E0E8753D /* DuressModeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F5B696CF0677865FA2C /* DuressModeViewModel.swift */; }; 11B3543EF331DA9E5E33822A /* SingleCoinPriceEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E514EF2784402C7DC2A /* SingleCoinPriceEntry.swift */; }; @@ -450,8 +433,6 @@ 11B354BC4D954CCDA2E75C68 /* AddEvmSyncSourceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350B29037572DDAAF9E16 /* AddEvmSyncSourceViewModel.swift */; }; 11B354C1218C0776499FAA5E /* Kmm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D813B2B43683404CCD6 /* Kmm.swift */; }; 11B354CAD4BC4FAB3889838D /* EvmSyncSourceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D9C2409FD9060974F67 /* EvmSyncSourceManager.swift */; }; - 11B354CBCCB0FFD2FDBEE757 /* MarketFilteredListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35ADF9BC4D149F86F23E4 /* MarketFilteredListService.swift */; }; - 11B354CC5E68F04E22D633D9 /* TopPlatformHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357E05A8AF5608ECF5D5F /* TopPlatformHeaderCell.swift */; }; 11B354CF393A2EAFDABE1C47 /* WalletTokenListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357D222B4819BE881E182 /* WalletTokenListViewController.swift */; }; 11B354D628AADF3AFD9123E1 /* SingleCoinPriceWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351F5E57874D4517F67B7 /* SingleCoinPriceWidget.swift */; }; 11B354D6DE193776FFACE1B5 /* AddEvmSyncSourceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351F33517C6DDA1E7AF59 /* AddEvmSyncSourceViewController.swift */; }; @@ -463,7 +444,6 @@ 11B354E72D9BDF04E75C8748 /* WalletHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3597A2B0B529BE97F85C8 /* WalletHeaderCell.swift */; }; 11B354E85FD7EE82D34FD1C4 /* BalanceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BB7206DA0EDBB43C814 /* BalanceCell.swift */; }; 11B354EB71E52DF79A003231 /* FaqUrlHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35759E226171A4969E66E /* FaqUrlHelper.swift */; }; - 11B354ECE594CE629BA46BE1 /* MarketCategoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352AC4F5BE70D055293D7 /* MarketCategoryViewModel.swift */; }; 11B354EE16A63DAD95DE3861 /* ManageWalletsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3550ED151B4C6824B9779 /* ManageWalletsViewModel.swift */; }; 11B354EFE4620A8E65D44335 /* WalletViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357426B767AA64ED8E7A2 /* WalletViewModel.swift */; }; 11B354F237E59C24ED8F3759 /* TokenQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353684493AFDF3711DF2B /* TokenQuery.swift */; }; @@ -494,7 +474,6 @@ 11B3552937152C5A4169C018 /* PasscodeLockManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3505A43D9C2787B3BD153 /* PasscodeLockManager.swift */; }; 11B35529AB46C98BC35C72E4 /* CoinPriceListProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EE1C1F555F4160AC201 /* CoinPriceListProvider.swift */; }; 11B35530A9FC0972D8716C31 /* ValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357A5569EAC7D20CD40B2 /* ValueFormatter.swift */; }; - 11B3553109794AE192BF7591 /* MarketCategoryModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350CAB1C54A2CAA4C76F6 /* MarketCategoryModule.swift */; }; 11B35531B3F80D06EF040301 /* CoinType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357B2D07C69579BAEC997 /* CoinType.swift */; }; 11B355342F86DF79AE7000B9 /* Cex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D6718A1DEB73A0CEC02 /* Cex.swift */; }; 11B35538EF749777CF7B2E8B /* ChartUiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DE812F995B07C8F0B01 /* ChartUiView.swift */; }; @@ -520,7 +499,6 @@ 11B355734D16C412220BBEBD /* NftKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35665980CEA4D009A9B77 /* NftKit.swift */; }; 11B35573BC52BFE9E545AA01 /* GuideCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EC5CADBD290DDD3DE1C /* GuideCell.swift */; }; 11B355756A2457C64C969024 /* CoinCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357C17104792A20769560 /* CoinCategory.swift */; }; - 11B35577071CBB59D7692DE4 /* MarketTopPairsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C5CA7497C540FFC5D39 /* MarketTopPairsViewController.swift */; }; 11B3557AF8D64E9897965526 /* ISendData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355A2FFA369C4E89DFF53 /* ISendData.swift */; }; 11B3557CB2595D2884C94498 /* MultiTextMetricsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359824DCDF3B05413CDD2 /* MultiTextMetricsView.swift */; }; 11B3557D484786A0D41E16AF /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357736B8C29DF38F5DCBA /* AlertViewController.swift */; }; @@ -547,7 +525,6 @@ 11B355BDD19498AA9CD250BB /* LanguageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3508A186E4CC100967FD3 /* LanguageSettingsView.swift */; }; 11B355C5BB0C447A0395168C /* GuidesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D9767615D8FBF7A314F /* GuidesManager.swift */; }; 11B355C78B016FC2EDDAECCC /* SendEvmModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3515139F2682C9C733F3D /* SendEvmModule.swift */; }; - 11B355C8567EB1690E3BDA77 /* MarketOverviewService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3554159E6E5B7C1E71F04 /* MarketOverviewService.swift */; }; 11B355CA37285348558E98A9 /* SwitchAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352E8A5E0463B30001AFE /* SwitchAccountViewController.swift */; }; 11B355D89EADD907D4FC3273 /* MultiSwapButtonState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35140CD5BF8B1C26A6278 /* MultiSwapButtonState.swift */; }; 11B355DB012D5856C675FE72 /* CreateAccountService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3592A5323E54639864FC7 /* CreateAccountService.swift */; }; @@ -569,7 +546,6 @@ 11B35608F7D19B3E6318CB22 /* Text.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352972B14FA6EBEFD6904 /* Text.swift */; }; 11B3560E158C55624C466E27 /* GuidesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E511F9D2B6C65792324 /* GuidesViewController.swift */; }; 11B3560F69D84432665A2BAA /* CoinPageViewModelNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3529DC8E74672659515B8 /* CoinPageViewModelNew.swift */; }; - 11B35611F21D266215BD82A5 /* MarketOverviewTopPairsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350465C489A233625E8F2 /* MarketOverviewTopPairsDataSource.swift */; }; 11B3561679C05C31F16EDC77 /* BaseUnlockViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351F8A0A9EB045377C152 /* BaseUnlockViewModel.swift */; }; 11B3561A469C906B67F24459 /* FeeRateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359BBFCD82C3C6DC06F96 /* FeeRateProvider.swift */; }; 11B3561E7DF566A274210E01 /* EvmSyncSourceRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B56F5C8138085588EE5 /* EvmSyncSourceRecord.swift */; }; @@ -598,7 +574,6 @@ 11B356562D2B4F5BCAB4FC80 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357C3907AC1134C7A95DB /* AboutView.swift */; }; 11B3565D4E4EAD663143ED9B /* BaseCurrencySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D203692A7F12D67242D /* BaseCurrencySettingsView.swift */; }; 11B3565DC90BD451F8DE7120 /* EvmSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B0F9BC5C4CDBC5B041D /* EvmSendHandler.swift */; }; - 11B35664B1EDEAB99B7B51AE /* MarketCategoryModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350CAB1C54A2CAA4C76F6 /* MarketCategoryModule.swift */; }; 11B356655BCF0A3919AD5120 /* ActivateSubscriptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3508AB65CCBDC18FEF2A6 /* ActivateSubscriptionViewController.swift */; }; 11B35665CC02390699802C61 /* RestoreBinanceModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35995E0D358AC4DA2FA74 /* RestoreBinanceModule.swift */; }; 11B3566FB55E128CD6F22DAE /* TransactionSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3514BFFAE3CE09F4DB2EA /* TransactionSettings.swift */; }; @@ -632,7 +607,6 @@ 11B356C6FEEFD7A1B854FB46 /* AccountRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E9B9C7A88B7584507DF /* AccountRecord.swift */; }; 11B356C983C2A2B552D214A4 /* ListSectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352970EA9924258E5BB75 /* ListSectionFooter.swift */; }; 11B356CF0D78F2DC6F28B4BD /* LaunchErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A4096D259C9B1540D10 /* LaunchErrorViewController.swift */; }; - 11B356CF55DB1BE22071B24E /* MarketMultiSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350FAB6F1A6E1FCFACB2F /* MarketMultiSortHeaderViewModel.swift */; }; 11B356D4E85B0A0133F6870C /* RestorePrivateKeyService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351EBA5DE11150CE2E3F9 /* RestorePrivateKeyService.swift */; }; 11B356D60C39544F165547AA /* TermsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351DAF31FBE0834EBC066 /* TermsService.swift */; }; 11B356D67F706464900DBD25 /* CexCoinService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3590EB4E34B278277E8E4 /* CexCoinService.swift */; }; @@ -676,7 +650,6 @@ 11B3573B753DB244EEBAAA35 /* ReceiveSelectCoinViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358B8D6DFEAEDE84D53DE /* ReceiveSelectCoinViewController.swift */; }; 11B3573B8B8DA5C1DE332EB6 /* EvmNetworkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35711A471C5A45DD87108 /* EvmNetworkViewController.swift */; }; 11B3573F7ED8577EF9F12EF9 /* EvmAccountRestoreStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350A3E8F85D6FA2E17173 /* EvmAccountRestoreStateManager.swift */; }; - 11B357405174FF9F9BEB3704 /* MarketTopModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F9DA79410E7B9C1B0F8 /* MarketTopModule.swift */; }; 11B357408E3CCC0B93C42F67 /* WCSignEthereumTransactionRequestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A74A323368707589FA3 /* WCSignEthereumTransactionRequestViewModel.swift */; }; 11B3574287AAA5FC16E3E3DA /* NavigationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3578FB80AA013BD351A26 /* NavigationRow.swift */; }; 11B35749EBFB7FE593BECE9E /* ExtendedKeyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F95A84DD0F232E5A9CD /* ExtendedKeyViewModel.swift */; }; @@ -709,7 +682,6 @@ 11B357BADA228BE93B8451E7 /* AddEvmSyncSourceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350B29037572DDAAF9E16 /* AddEvmSyncSourceViewModel.swift */; }; 11B357BD9D9681D0D79DDEBE /* UITabBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350369A891BEA3A525E5B /* UITabBarItem.swift */; }; 11B357BF378060E7E35F7052 /* AdditionalDataCellNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E67C1B1AB7A13074894 /* AdditionalDataCellNew.swift */; }; - 11B357BF7588CB317EA62167 /* MarketOverviewCategoryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A0AF4D03160AF66D1D9 /* MarketOverviewCategoryService.swift */; }; 11B357C425D633543FD109C3 /* DuressModeSelectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3554BC96C9C24C24CC2B0 /* DuressModeSelectView.swift */; }; 11B357C5FC1B7FDE86244DA5 /* SingleSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CAE2327342F9CEC6AC9 /* SingleSelectorViewController.swift */; }; 11B357D1A2BD673DAB7B4C61 /* SecondaryButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3587A6A05EFF1036F6C4B /* SecondaryButtonCell.swift */; }; @@ -742,7 +714,6 @@ 11B3580BC3B5D2CBC68854D2 /* UIWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353356496AA219686B993 /* UIWindow.swift */; }; 11B3580CD18A931ABAA6C122 /* BiometryType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359A35AEB7964A94AFFC0 /* BiometryType.swift */; }; 11B3580E4A964C65BF8EDDE9 /* StackViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AAE4114A56DF13ECF0F /* StackViewCell.swift */; }; - 11B358122FE64E16EC25F095 /* MarketOverviewService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3554159E6E5B7C1E71F04 /* MarketOverviewService.swift */; }; 11B358137165A40C30218032 /* TermsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B462980B0617E11FB05 /* TermsModule.swift */; }; 11B358164F9FBBE78CBC806A /* NftActivityModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35252F90F25774BDD2CB3 /* NftActivityModule.swift */; }; 11B35819C7596909297311B2 /* Eip20Kit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3524B273DD5AB2FF5C7A6 /* Eip20Kit.swift */; }; @@ -776,7 +747,6 @@ 11B3586009D99341D46E1824 /* GuideCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EC5CADBD290DDD3DE1C /* GuideCell.swift */; }; 11B358622B30F9ED5B734A94 /* WalletHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3597A2B0B529BE97F85C8 /* WalletHeaderCell.swift */; }; 11B358623111DC1A8ED499DC /* EvmAddressViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35962622F74F89FD32D2B /* EvmAddressViewModel.swift */; }; - 11B358634BEC799056209B93 /* MarketTopPairsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355C615D9FE4290671D5D /* MarketTopPairsModule.swift */; }; 11B358657FCC50C9B3A10294 /* ManageWalletsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C4D645B4468F84EADB7 /* ManageWalletsViewController.swift */; }; 11B3586BF6AC0538272E71A4 /* NftCollectionModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35708A630D70385F34A8B /* NftCollectionModule.swift */; }; 11B3586F6BFCA16BDFD5921D /* DuressModeModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A81FB3D4C06BBFEE7E7 /* DuressModeModule.swift */; }; @@ -795,7 +765,6 @@ 11B3588E8DA44A45661351D7 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35614C6E244926AF48701 /* Account.swift */; }; 11B358902CE8D7EF2AD38448 /* CoinService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3550B863970039577CD00 /* CoinService.swift */; }; 11B35890939A3326B352A0FB /* ActiveAccountStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354C4B46DF1A50103F026 /* ActiveAccountStorage.swift */; }; - 11B358946C5E7A72712EACB2 /* MarketCategoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DB992C240A4CF24938A /* MarketCategoryView.swift */; }; 11B3589541E87A032D9D2D50 /* BottomSingleSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EF3688D60C8E6823267 /* BottomSingleSelectorViewController.swift */; }; 11B35895C483A56545A6700E /* CexDepositNetworkSelectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C227EDC2D4ED188A0FC /* CexDepositNetworkSelectViewController.swift */; }; 11B35897566548048FCEC11E /* WalletBlockchainElementService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AE5785634316A1A5DA8 /* WalletBlockchainElementService.swift */; }; @@ -839,11 +808,8 @@ 11B358E7A9BC36B1B562A5B4 /* NftMetadataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359FE71F5DE6AAD2BA3D8 /* NftMetadataManager.swift */; }; 11B358EC0A19773B1455CF62 /* LockoutManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3576F224007FD4154EBE8 /* LockoutManager.swift */; }; 11B358EC68642C5A57ACB803 /* IMultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357975CCFB31CCEF29F97 /* IMultiSwapProvider.swift */; }; - 11B358F04D8F15D43CB2BAA6 /* MarketCategoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DB992C240A4CF24938A /* MarketCategoryView.swift */; }; 11B358F1E7C72C1F42EC456F /* CoinToggleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350CDE31673BA1673B620 /* CoinToggleViewModel.swift */; }; 11B358F2CD17616038016E59 /* NftRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354B32BD428041237570A /* NftRecord.swift */; }; - 11B358F511E01944DA31FF7D /* MarketListMarketPairDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3557E5ACDC89EF79C8C0C /* MarketListMarketPairDecorator.swift */; }; - 11B358F9D6842ECD84E80752 /* MarketCategoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352AC4F5BE70D055293D7 /* MarketCategoryViewModel.swift */; }; 11B3590189E28D408E207E19 /* CexDepositService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356B9F833E1AEE0D6D589 /* CexDepositService.swift */; }; 11B35902128F12FB06B0CA5E /* BaseUnlockViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351F8A0A9EB045377C152 /* BaseUnlockViewModel.swift */; }; 11B359029FFF4106B703694C /* CexDepositNetworkSelectModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BBC5BBCC258824A80F3 /* CexDepositNetworkSelectModule.swift */; }; @@ -860,7 +826,6 @@ 11B35920CB7EA5E3322F6D7F /* InputStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353BA87FDCB1BCBA92E61 /* InputStackView.swift */; }; 11B359264A7E2CFD0925A778 /* CoinMajorHoldersService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C6498078B1AFF406256 /* CoinMajorHoldersService.swift */; }; 11B35927C89712EF8ED36981 /* InputRowModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B7E25636164A4B65CEC /* InputRowModifier.swift */; }; - 11B35929AD3C9F27463392C6 /* TopPlatformViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BB370AE2C896BB9F877 /* TopPlatformViewController.swift */; }; 11B3592EC9C229FD531ED6B5 /* BalanceButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3585EF1DA625D906AF9B5 /* BalanceButtonsView.swift */; }; 11B3593134900A8FC7C075B6 /* NftService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355129D9F61172FCAB8C0 /* NftService.swift */; }; 11B359330CB6A60E5960CEC2 /* CoinMarketsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BFB11BC4B9FF7D53B8D /* CoinMarketsView.swift */; }; @@ -872,7 +837,6 @@ 11B3594DD9B54E11190B4CD5 /* PoolProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359636E1AA1BC72CF7B11 /* PoolProvider.swift */; }; 11B3594FCD35038663CD4FEF /* ReceiveViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CFED85A9315089223E3 /* ReceiveViewModel.swift */; }; 11B3594FF624369050E43F8F /* SendData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AD24681D0A122E6A3C5 /* SendData.swift */; }; - 11B359515EE181B7C3D773D3 /* MarketOverviewTopPlatformsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3582259AD3A0C55CF6D2C /* MarketOverviewTopPlatformsService.swift */; }; 11B35951600F986F1C424E24 /* PasscodeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B5570E7513DF2A455BB /* PasscodeManager.swift */; }; 11B359528BEC580E0BE7E7D3 /* ValueLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355166E437B7ADB8B8EBA /* ValueLevel.swift */; }; 11B35953182487E864EB4946 /* ActivateSubscriptionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351E1107158B6A2BF2149 /* ActivateSubscriptionService.swift */; }; @@ -931,7 +895,6 @@ 11B359BF322A7B912C778348 /* WatchlistWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B0879F715C0777919AA /* WatchlistWidget.swift */; }; 11B359C05619611CBCFC89AC /* EvmBlockchainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356D15E318829D9C7F5F1 /* EvmBlockchainManager.swift */; }; 11B359C198AA7A141522E5E9 /* EvmAccountManagerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F980B34E005B9F02B8F /* EvmAccountManagerFactory.swift */; }; - 11B359C2651DA1F00A3C613C /* CoinRankViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359575A4E090B236E84C7 /* CoinRankViewModel.swift */; }; 11B359C5A1F97662FDD57259 /* RestoreSettingRecord_v_0_25.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DFA83DA24A00D73EA7D /* RestoreSettingRecord_v_0_25.swift */; }; 11B359C829669CC55E530476 /* ExtendedKeyModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351F1248EDA20F7141AB8 /* ExtendedKeyModule.swift */; }; 11B359CF6F464D59295B7B31 /* SelectorButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3589B8D488ED1F6912287 /* SelectorButtonStyle.swift */; }; @@ -973,7 +936,6 @@ 11B35A3C2C4CC7A834D56517 /* MultiSwapPreSwapStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358DD4F0C5E4E5A4EEBA4 /* MultiSwapPreSwapStep.swift */; }; 11B35A3FD624D80C6D98A1CF /* TransactionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D6BAEC40B3DA7A1FE95 /* TransactionSource.swift */; }; 11B35A40665567C6CE6EEBCC /* LanguageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3508A186E4CC100967FD3 /* LanguageSettingsView.swift */; }; - 11B35A426FD3D729DEB89DEA /* MarketTopViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3505AD2C1640DEAD8CFFC /* MarketTopViewController.swift */; }; 11B35A42BF19B93C6005FBD9 /* AddTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356FFA77A8F6918B13FCA /* AddTokenService.swift */; }; 11B35A42D28B8BC4CDA57D8E /* AccountRecord_v_0_19.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350F6C5F6ABC288511AF0 /* AccountRecord_v_0_19.swift */; }; 11B35A4428B94FF4E4F01AA9 /* SendData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AD24681D0A122E6A3C5 /* SendData.swift */; }; @@ -986,7 +948,6 @@ 11B35A4F54E1310A7963593F /* PrivateKeysModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D55BE7717A87DA6FC43 /* PrivateKeysModule.swift */; }; 11B35A51BDF5BA34DA7B227E /* CexDepositNetworkSelectModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BBC5BBCC258824A80F3 /* CexDepositNetworkSelectModule.swift */; }; 11B35A52C122A756C0A43604 /* PrimaryButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354E55E901615862E7CD4 /* PrimaryButtonCell.swift */; }; - 11B35A5A820C1BCC1A92E944 /* MarketTopViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3505AD2C1640DEAD8CFFC /* MarketTopViewController.swift */; }; 11B35A5B22BD628721B47E09 /* ScanQrBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351454D8FE8FEDA2C1EC9 /* ScanQrBlurView.swift */; }; 11B35A5B8DC265D419E69B05 /* CexAssetResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357C67623035CDF98B540 /* CexAssetResponse.swift */; }; 11B35A5C28DF128893703B6C /* RestoreViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3518EEF5AFC1C55FD07BA /* RestoreViewModel.swift */; }; @@ -1005,8 +966,6 @@ 11B35A82220538FEE57546FB /* TransactionTypeFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3592E4DA65E72C0BC6BEB /* TransactionTypeFilter.swift */; }; 11B35A82532EC55909EFBAD8 /* LaunchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3595BAA550B6BEC8C3F72 /* LaunchScreen.swift */; }; 11B35A8395C75C6FA6515F3C /* CexWithdrawViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35ABC3E6C990E3BFA0A7B /* CexWithdrawViewController.swift */; }; - 11B35A89B3F0D81C42DC5C40 /* CoinRankHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351664970D7EA1F7B50C7 /* CoinRankHeaderView.swift */; }; - 11B35A8BB87C68ACF4594C99 /* MarketTopModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F9DA79410E7B9C1B0F8 /* MarketTopModule.swift */; }; 11B35A8D8CA77B42650F4C03 /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351958604DF0B0AB3346C /* Publisher.swift */; }; 11B35A90F19DE20ABE21F423 /* AddTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356FFA77A8F6918B13FCA /* AddTokenService.swift */; }; 11B35A91D104DA35C08032B2 /* AccountType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35542A7D7FE1BDC2E73E2 /* AccountType.swift */; }; @@ -1047,7 +1006,6 @@ 11B35AF420F4D90CD6C9E6E3 /* OneInchMultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EF841FD4B3D13058F76 /* OneInchMultiSwapProvider.swift */; }; 11B35AF710C287EB89018342 /* UIWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353356496AA219686B993 /* UIWindow.swift */; }; 11B35AF765474AEE15CA4240 /* AccountRecord_v_0_20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3506CB3D780A00F4BBBBE /* AccountRecord_v_0_20.swift */; }; - 11B35B02E53E6D7DDC12FC5D /* MarketOverviewTopPairsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352BDC42A2F717AFAE7BD /* MarketOverviewTopPairsService.swift */; }; 11B35B077A52041C9939C6E8 /* FaqCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3528090862B6792A76DA4 /* FaqCell.swift */; }; 11B35B086B0D62A9D7A10CD0 /* AddTokenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355E8892971578502EF33 /* AddTokenViewModel.swift */; }; 11B35B09AADB1FBF7DDE765C /* TransactionFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3567314F1A1DF8D1B2910 /* TransactionFilterView.swift */; }; @@ -1074,7 +1032,6 @@ 11B35B3821C6CCB647B98F9A /* MarkdownService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35801399EA004F5A2A1F7 /* MarkdownService.swift */; }; 11B35B3C7A60FEE011EFBF73 /* InputSecondaryCircleButtonWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3573AF91C82342639A9B1 /* InputSecondaryCircleButtonWrapperView.swift */; }; 11B35B3F384758B223A7218C /* MainSettingsFooterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BD9A836C953CCF8D077 /* MainSettingsFooterCell.swift */; }; - 11B35B3F5DE4F73225EBFF36 /* CoinRankViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359575A4E090B236E84C7 /* CoinRankViewModel.swift */; }; 11B35B40461A5D9841EEE4EF /* StatRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B9F4421EE65B8B09370 /* StatRecord.swift */; }; 11B35B501A30615698B04C96 /* AddEvmTokenBlockchainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352ABFDEAEEA84D3FDD8B /* AddEvmTokenBlockchainService.swift */; }; 11B35B507F2F843A5B3E4C7C /* EvmNetworkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351895EE2816DE7BBC767 /* EvmNetworkViewModel.swift */; }; @@ -1092,7 +1049,6 @@ 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 */; }; - 11B35B970E8949F968960796 /* MarketListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3596381A93F3A3D2575D6 /* MarketListViewController.swift */; }; 11B35B99BA314135CB139D02 /* WCSignEthereumTransactionRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BEA44ADC0D844330FB7 /* WCSignEthereumTransactionRequestViewController.swift */; }; 11B35B99C84075296D6F26DE /* UnlinkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35419B0C846238DDC50F3 /* UnlinkViewModel.swift */; }; 11B35B9BCE8AF0B54BFBED42 /* BalanceButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3585EF1DA625D906AF9B5 /* BalanceButtonsView.swift */; }; @@ -1112,7 +1068,6 @@ 11B35BC7BBEFE0AB8D8FE405 /* CexCoinSelectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352F071CE0EF1505A8380 /* CexCoinSelectViewController.swift */; }; 11B35BCC6C00E857CE562F16 /* EvmAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352D314A298B6B832F309 /* EvmAdapter.swift */; }; 11B35BCD6D0462E31D7EBA06 /* BackupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355E86612AEE00ED19CFE /* BackupManager.swift */; }; - 11B35BCF9FFC93255EFB2774 /* CoinRankHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351664970D7EA1F7B50C7 /* CoinRankHeaderView.swift */; }; 11B35BD102629037A4348B3C /* WCSignEthereumTransactionRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BEA44ADC0D844330FB7 /* WCSignEthereumTransactionRequestViewController.swift */; }; 11B35BD170E89520DF7D384E /* BaseUniswapMultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D67C8EEB29CB302973A /* BaseUniswapMultiSwapProvider.swift */; }; 11B35BDBD856C645045553D2 /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3572B7C2F16CD51F37FF0 /* UIImage.swift */; }; @@ -1145,7 +1100,6 @@ 11B35C2D31DE8081AC572B27 /* BaseUniswapV2MultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358A102692DA01F91413D /* BaseUniswapV2MultiSwapProvider.swift */; }; 11B35C2D75133B8F13101A24 /* BalancePrimaryValueManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3566DC3A97A5CC3E2C729 /* BalancePrimaryValueManager.swift */; }; 11B35C2EB8D6EC593915640F /* CexDepositModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35011026CE084AE40FE6F /* CexDepositModule.swift */; }; - 11B35C2ED09C6D5660BB1236 /* MarketWatchlistToggleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3562819DF141457837340 /* MarketWatchlistToggleService.swift */; }; 11B35C2F43F8135F22DD7FDF /* ActivateSubscriptionModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35997A9E413878F48313B /* ActivateSubscriptionModule.swift */; }; 11B35C2FBF875F81E13CC575 /* CoinService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3550B863970039577CD00 /* CoinService.swift */; }; 11B35C3418D6E7D94CB5C2AF /* RecoveryPhraseService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351A0B1AE5F612E6A5FEE /* RecoveryPhraseService.swift */; }; @@ -1158,21 +1112,16 @@ 11B35C47A06C0A4F7231C511 /* NftCollectionAssetsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35100DD6E2DBF905FD19B /* NftCollectionAssetsModule.swift */; }; 11B35C4875DAA9A92BD9B7EC /* CoinMajorHoldersService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C6498078B1AFF406256 /* CoinMajorHoldersService.swift */; }; 11B35C4A0250F05179488A91 /* CexWithdrawNetworkRaw.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35EC03BB5316524050518 /* CexWithdrawNetworkRaw.swift */; }; - 11B35C4A68DD7F7AF6DC4F27 /* TopPlatformViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3527F1528AA697AAA6E61 /* TopPlatformViewModel.swift */; }; 11B35C4D4120D85CD32CAD0F /* TransactionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350CCAA0C9F2F5279F680 /* TransactionsViewController.swift */; }; 11B35C4E01C2AF2707691B96 /* CurrencyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE8A0802ADE2FAB0012DE7F /* CurrencyManager.swift */; }; 11B35C5388370450DAF65C5B /* EvmUpdateStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E5C80435645132BCDD2 /* EvmUpdateStatus.swift */; }; 11B35C59583AFCDFD828B9D1 /* TextFieldStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35921FBDF6F9BBAA88803 /* TextFieldStackView.swift */; }; - 11B35C5E7A90AA7B302EB0CD /* MarketListMarketFieldDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353B060BDF272932D3522 /* MarketListMarketFieldDecorator.swift */; }; 11B35C5F856FB531028F8C0A /* CreateDuressPasscodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3501625BDD3F7D9BEA2F5 /* CreateDuressPasscodeViewModel.swift */; }; 11B35C60FE9B94994FCCB0CB /* TonTransactionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A67733FE53B31E5EB3A /* TonTransactionRecord.swift */; }; 11B35C68D57727AB0DAC7753 /* NftAddressMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BEEB24CDB82D3F4E7C0 /* NftAddressMetadata.swift */; }; - 11B35C72EF5FB79182EAB119 /* MarketTopPairsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359715B07FD5316D72A07 /* MarketTopPairsViewModel.swift */; }; 11B35C7425B861D2F32384E8 /* ListSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350C0CB7083E2738D356C /* ListSectionHeader.swift */; }; 11B35C78C16D1F89FBC8F222 /* ReceiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359D1A38D53951CEE6F84 /* ReceiveViewController.swift */; }; 11B35C7BB534F9FFE5B6B3A6 /* TokenType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3519AE11DC423E0D078E2 /* TokenType.swift */; }; - 11B35C81D9DFBF07955D2461 /* CoinRankModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358A22655004017228F65 /* CoinRankModule.swift */; }; - 11B35C83BC2D0EA7FF5B4832 /* MarketCategoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3584888F2DB8CCFAA90DF /* MarketCategoryViewController.swift */; }; 11B35C8621E221DA1F157A5B /* AccountFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C4D6F474C2EB3687EB4 /* AccountFactory.swift */; }; 11B35C88ACACE26AC40F35BA /* PrimaryButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35968D12AAAC828AFE955 /* PrimaryButtonStyle.swift */; }; 11B35C8A1082D0A8F0B354B1 /* RestoreMnemonicHintCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358604E6B530C5DB22B92 /* RestoreMnemonicHintCell.swift */; }; @@ -1180,7 +1129,6 @@ 11B35C8A95E4C8D43F9279B6 /* EvmLabelStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F007444A766AF8CD20D /* EvmLabelStorage.swift */; }; 11B35C8BF55C38F198C3DAE6 /* BadgeViewNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352BD333C9D69ECB82884 /* BadgeViewNew.swift */; }; 11B35C8D53F838E7E5CA6EEC /* NftStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3502AEB7EF95A590A7B1B /* NftStorage.swift */; }; - 11B35C8E09922F59B200E347 /* MarketListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3596381A93F3A3D2575D6 /* MarketListViewController.swift */; }; 11B35C906C5278060BD5A04C /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351E61AB3FB570A4F7C66 /* Wallet.swift */; }; 11B35C943710774694282388 /* IMultiSwapQuote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350F532661482B6170F92 /* IMultiSwapQuote.swift */; }; 11B35C9570D3C283E9C943D5 /* CreatePasscodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3590ACA8DFA4196E8EC33 /* CreatePasscodeViewModel.swift */; }; @@ -1188,7 +1136,6 @@ 11B35CA25E02E397E167EEC3 /* QrCodeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356F4578E266268264021 /* QrCodeCell.swift */; }; 11B35CA4F61231F536BE9A24 /* PancakeV2MultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3564500A3378D6EB2A477 /* PancakeV2MultiSwapProvider.swift */; }; 11B35CA6259EDA3708695416 /* FaqUrlHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35759E226171A4969E66E /* FaqUrlHelper.swift */; }; - 11B35CA725B9BAD70E40197F /* MarketTopPairsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355C615D9FE4290671D5D /* MarketTopPairsModule.swift */; }; 11B35CA92AA402BE72B4F5D6 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352648C452D611F1EDF61 /* Image.swift */; }; 11B35CAD54059FA55DF81972 /* PasscodeLockManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3505A43D9C2787B3BD153 /* PasscodeLockManager.swift */; }; 11B35CAD5A7E0C8709559FD2 /* WalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352D547F1BB38D2AD6AD5 /* WalletManager.swift */; }; @@ -1205,12 +1152,9 @@ 11B35CC202B611609C8445A4 /* BaseUniswapV3MultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351FAE6B01F29FC37B3C2 /* BaseUniswapV3MultiSwapProvider.swift */; }; 11B35CC30F65AC6966F66BA4 /* MarkdownViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359B9C1E0BB4D32599695 /* MarkdownViewModel.swift */; }; 11B35CC39C37FD31AA98A105 /* CoinMajorHoldersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AB755E196D299B81BFB /* CoinMajorHoldersViewController.swift */; }; - 11B35CC691C53A0B870BB910 /* MarketFilteredListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35ADF9BC4D149F86F23E4 /* MarketFilteredListService.swift */; }; 11B35CC9464E639F3A086B29 /* MarkdownHeader1Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D31D3EC415789CFA160 /* MarkdownHeader1Cell.swift */; }; 11B35CCAC0A3C35C1B9BD918 /* NftActivityViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DE76BBABD8F0914A0D2 /* NftActivityViewModel.swift */; }; - 11B35CCC81AE83E1CBB61504 /* MarketMultiSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350FAB6F1A6E1FCFACB2F /* MarketMultiSortHeaderViewModel.swift */; }; 11B35CCC9D6B7596502B4381 /* CoinInvestment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35264F7CE80AD5D9A540A /* CoinInvestment.swift */; }; - 11B35CD199C820EC89FBB546 /* MarketListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355BEB95969D89B3F8876 /* MarketListViewModel.swift */; }; 11B35CD742378BF04CDB73F0 /* NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350BD364F07D1AC759865 /* NSAttributedString.swift */; }; 11B35CDC811A92DFAAF2C923 /* ListSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350C0CB7083E2738D356C /* ListSectionHeader.swift */; }; 11B35CE67B7F5C5A5244C951 /* MainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B6D6FCA3745DE0750BD /* MainService.swift */; }; @@ -1221,8 +1165,6 @@ 11B35D0542ACB56A31C61143 /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3572B7C2F16CD51F37FF0 /* UIImage.swift */; }; 11B35D05FF90E999110698C0 /* RecipientAddressInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DBDADDA8D4F9D88C7AA /* RecipientAddressInputCell.swift */; }; 11B35D06AFC1BAC63F25D271 /* CoinAnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35996D668B9ADC60E6B9B /* CoinAnalyticsService.swift */; }; - 11B35D06C75228488867EB22 /* MarketOverviewTopPlatformsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3582259AD3A0C55CF6D2C /* MarketOverviewTopPlatformsService.swift */; }; - 11B35D06FF4A25AF74553C36 /* MarketOverviewTopPairsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AB1D0CE5D8ECE7DDF65 /* MarketOverviewTopPairsViewModel.swift */; }; 11B35D098F3E0435A3C4512B /* MultiSwapButtonState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35140CD5BF8B1C26A6278 /* MultiSwapButtonState.swift */; }; 11B35D09F6CBE8A070C415F7 /* WalletTokenListViewItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C6E5282F55B88042F8D /* WalletTokenListViewItemFactory.swift */; }; 11B35D106185086B3BEC5119 /* Blockchain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3595BAB29E195A1317DD1 /* Blockchain.swift */; }; @@ -1232,18 +1174,15 @@ 11B35D11D00301F7B67B0340 /* AppIconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A309C359456D7DF1A03 /* AppIconManager.swift */; }; 11B35D16F2F7B8E11A771B18 /* FavoriteCoinRecord_v_0_38.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E255F6CA21FFA9E6B42 /* FavoriteCoinRecord_v_0_38.swift */; }; 11B35D19D00091E903B04472 /* MarkdownViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DF08505C3A7CB1BBBB4 /* MarkdownViewController.swift */; }; - 11B35D1F6602B517D19D5C76 /* TopPlatformViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BB370AE2C896BB9F877 /* TopPlatformViewController.swift */; }; 11B35D24064D9CE75ACCD59A /* CoinAnalyticsIssuesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35466E6DC969B551B10D3 /* CoinAnalyticsIssuesView.swift */; }; 11B35D24B98C73BD43CCD80B /* NftAssetRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359852B313E849499BC19 /* NftAssetRecord.swift */; }; 11B35D270BF38B1478789B5E /* MarkdownService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35801399EA004F5A2A1F7 /* MarkdownService.swift */; }; - 11B35D2B9A488D3382D8693D /* MarketHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3543F4D196A47EFE3E6F7 /* MarketHeaderCell.swift */; }; 11B35D2C16299881FE8BD910 /* MultiSwapQuotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35062C72B1D98A2A4EDA9 /* MultiSwapQuotesView.swift */; }; 11B35D2C28E3116F58A543E2 /* BtcBlockchainSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35469BE6FC454CD6D15B5 /* BtcBlockchainSettingsService.swift */; }; 11B35D3102B803096B6EE5B6 /* NftMetadataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359FE71F5DE6AAD2BA3D8 /* NftMetadataManager.swift */; }; 11B35D39722C76466D6397F3 /* CexCoinSelectViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B2E5AB093ABD8228769 /* CexCoinSelectViewModel.swift */; }; 11B35D40702B98DD14429562 /* FormAmountInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352A41EC99ADCC8F3E3E9 /* FormAmountInputView.swift */; }; 11B35D45BA3D8B9C5E2AE4ED /* ManageWalletsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3529B6C7C426755CE9E14 /* ManageWalletsService.swift */; }; - 11B35D46B65772A1CC17B099 /* MarketGlobalTvlMetricViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8E1106E31D68FD9181D /* MarketGlobalTvlMetricViewController.swift */; }; 11B35D4B4DE7C4620C34AA11 /* AddEvmSyncSourceModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35504934CE3C31D523F82 /* AddEvmSyncSourceModule.swift */; }; 11B35D4CAE7D1CD1C169EDD4 /* TextDropDownAndSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359C62F476065C11EE049 /* TextDropDownAndSettingsView.swift */; }; 11B35D4CF0FBE2496CED70E4 /* EditPasscodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CF718BD36A9F07BC293 /* EditPasscodeViewModel.swift */; }; @@ -1273,11 +1212,9 @@ 11B35D835774B7F4E286BF32 /* AlertRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3516415E7A3217BBB1681 /* AlertRouter.swift */; }; 11B35D88633A14FD13E91702 /* TonAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F9B75F6663FAFCA3177 /* TonAdapter.swift */; }; 11B35D8E976E984302A81F8B /* ReceiveTokenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E1B9C559545FC3E6226 /* ReceiveTokenViewModel.swift */; }; - 11B35D90644F7735556DB3D5 /* TopPlatformViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3527F1528AA697AAA6E61 /* TopPlatformViewModel.swift */; }; 11B35D93B238BA992173E123 /* StackViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AAE4114A56DF13ECF0F /* StackViewCell.swift */; }; 11B35D94B4E92789F681E293 /* Coin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F3FBFB1F4BE93B796DF /* Coin.swift */; }; 11B35D95692647EB9F73D9DB /* CoinProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3534997B5CD413DBDB7C7 /* CoinProvider.swift */; }; - 11B35D96A814579F37BAD3D0 /* CoinRankService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3513AC6560B9C37C342F3 /* CoinRankService.swift */; }; 11B35DA1A83CE7E402309FE7 /* CreateAccountModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358145A0D9F93ACBC0301 /* CreateAccountModule.swift */; }; 11B35DA4CB435537AD4148D7 /* NftCollectionAssetsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3573B3FE1FD8B476375E6 /* NftCollectionAssetsViewModel.swift */; }; 11B35DA5492B0C4EC7130A19 /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3586FDC91E3742847B7E0 /* AppConfig.swift */; }; @@ -1308,7 +1245,6 @@ 11B35DF1D8B5125CF13A1812 /* RestoreMnemonicHintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CB288AF5A54B99A51E4 /* RestoreMnemonicHintView.swift */; }; 11B35DF3813AEB74E254A05A /* NftAssetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350E1584E954D281FA87D /* NftAssetView.swift */; }; 11B35DF625EA2A1412C2D984 /* DuressModeIntroView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35420841B4F9B886A6507 /* DuressModeIntroView.swift */; }; - 11B35DFCEC1D363B160479EE /* MarketTopService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35770F0C72E1CD3F99985 /* MarketTopService.swift */; }; 11B35DFF8F15AA74356061A0 /* ReceiveSelectCoinService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35615F3ECB5D6E467B49A /* ReceiveSelectCoinService.swift */; }; 11B35DFFC539A1E72382C8F7 /* ManageAccountsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350911E00460DA8925165 /* ManageAccountsService.swift */; }; 11B35DFFD52E10918F760DD5 /* InputSecondaryButtonWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D5C4EEEAABF83A67D95 /* InputSecondaryButtonWrapperView.swift */; }; @@ -1350,7 +1286,6 @@ 11B35E4FE3117F6B681F6748 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351E61AB3FB570A4F7C66 /* Wallet.swift */; }; 11B35E553176CF41B5CB83C0 /* BlockchainTokensView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F60AFA103D0CD2369C3 /* BlockchainTokensView.swift */; }; 11B35E57C6406D2249A23E6F /* SendEvmTransactionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C7F043B6C41E53D43BC /* SendEvmTransactionService.swift */; }; - 11B35E584C30C56AE18DE076 /* TopPlatformHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357E05A8AF5608ECF5D5F /* TopPlatformHeaderCell.swift */; }; 11B35E5DDFA437BD43717962 /* WalletViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35269B569B8588DB9A23C /* WalletViewController.swift */; }; 11B35E5EFE34BE1A3760F81D /* BiometryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A6223272C5B3E261A24 /* BiometryManager.swift */; }; 11B35E5F3C6070DF6E1F6BAD /* BlockchainType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357B185E8FECB3924FDF2 /* BlockchainType.swift */; }; @@ -1397,7 +1332,6 @@ 11B35EBC6D5608F23DF8581E /* EvmAccountRestoreStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350A3E8F85D6FA2E17173 /* EvmAccountRestoreStateManager.swift */; }; 11B35EBDDAB95E919600AE72 /* NftActivityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354FFF7ED1253E3BD804A /* NftActivityViewController.swift */; }; 11B35EBE688A7C4F9B92F865 /* ReceiveModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CF031BC81E4D401CA01 /* ReceiveModule.swift */; }; - 11B35EC2E4E5614FF64C7246 /* MarketMultiSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3503B9A985B4835FDB03D /* MarketMultiSortHeaderView.swift */; }; 11B35EC3B9E9C778183E1136 /* EvmNftAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C2397749C5654830540 /* EvmNftAdapter.swift */; }; 11B35ECCE5D888A506D7144A /* RestoreBinanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354D96A80987DAB3B64A6 /* RestoreBinanceViewController.swift */; }; 11B35ED22837284580055F0A /* BalanceData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BDEB703708795B71C4E /* BalanceData.swift */; }; @@ -1412,14 +1346,12 @@ 11B35EECB57465598F305C5B /* ListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351B200B193534D0A66BF /* ListRow.swift */; }; 11B35EEE72F3A78415A2A552 /* HorizontalDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D0EBAF33901578520E1 /* HorizontalDivider.swift */; }; 11B35EF433960198D484E5E8 /* ReceiveTokenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E1B9C559545FC3E6226 /* ReceiveTokenViewModel.swift */; }; - 11B35EF70120304F6D4F5561 /* MarketMultiSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3503B9A985B4835FDB03D /* MarketMultiSortHeaderView.swift */; }; 11B35EF9D9E8C1A814005CFD /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35747FAD8381F2AD48276 /* MainViewModel.swift */; }; 11B35EFAFFA1E30F7765FEB2 /* MainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B6D6FCA3745DE0750BD /* MainService.swift */; }; 11B35EFEEB7F361BD5FCCC3D /* SendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B91B5EAF2E193FDC04E /* SendView.swift */; }; 11B35F09A49A90BF058CA500 /* ReceiveSelectCoinViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350575488360C1A598DF3 /* ReceiveSelectCoinViewModel.swift */; }; 11B35F0D313E455BCF24C42B /* PriceChangeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357889F003A0B33D9DF27 /* PriceChangeType.swift */; }; 11B35F0FF89A5B636C2EFE48 /* UniswapV2MultiSwapProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350E65AAA33943BAD2F1D /* UniswapV2MultiSwapProvider.swift */; }; - 11B35F1152FB1004E554B922 /* MarketOverviewMetricsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DCCC2D8CD00EF6A9A77 /* MarketOverviewMetricsCell.swift */; }; 11B35F134E5EF8572BF330CB /* NavigationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3578FB80AA013BD351A26 /* NavigationRow.swift */; }; 11B35F1440C5946E9C3D94ED /* Auditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D8AF9D337A98530548D /* Auditor.swift */; }; 11B35F18FEEEAA9EC6043CA6 /* BaseCurrencySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D203692A7F12D67242D /* BaseCurrencySettingsView.swift */; }; @@ -1429,12 +1361,10 @@ 11B35F2474FF811217F48132 /* WalletHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E859456CF982321B46F /* WalletHeaderView.swift */; }; 11B35F25D1209C6DB33ADA55 /* AdapterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3583932F270503C1DF3F0 /* AdapterFactory.swift */; }; 11B35F27274120E53E2C1ADE /* Faq.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35450456BE5E3EE8F7391 /* Faq.swift */; }; - 11B35F28C21E228AB3158716 /* MarketOverviewMetricsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DCCC2D8CD00EF6A9A77 /* MarketOverviewMetricsCell.swift */; }; 11B35F29DCAF273D1092C0A4 /* PasscodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359FC4FE023FBA0E1726C /* PasscodeView.swift */; }; 11B35F2F1770FB757E6FDCD8 /* NftRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354B32BD428041237570A /* NftRecord.swift */; }; 11B35F3409AEFC534DC52137 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352978EC570F59F442BD5 /* View.swift */; }; 11B35F3525372880BC7B47DB /* EvmCoinServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35410733A35D1558E55B2 /* EvmCoinServiceFactory.swift */; }; - 11B35F3C9850408B9ADE0B16 /* DropdownSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F9BA41AC15436A4B977 /* DropdownSortHeaderView.swift */; }; 11B35F3DB270A794ADF675FB /* NoPasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356DAA35F1C6CCD7F25B5 /* NoPasscodeViewController.swift */; }; 11B35F3F123BFF155DA7F417 /* CoinAnalyticsHoldersCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359CE35C7483CCB956D13 /* CoinAnalyticsHoldersCell.swift */; }; 11B35F4294930802EC8C9CEA /* ReceiveAddressModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BB3B8928864A742C83E /* ReceiveAddressModule.swift */; }; @@ -1469,12 +1399,10 @@ 11B35F91AFFFD151AD80A625 /* ScanQrAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3560B257473CA93386D70 /* ScanQrAlertView.swift */; }; 11B35F91E53BA1F835DD4B4F /* HorizontalDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D0EBAF33901578520E1 /* HorizontalDivider.swift */; }; 11B35F98393E6F3B76381ECF /* ModuleUnlockViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B51E484CA62EC57790E /* ModuleUnlockViewModel.swift */; }; - 11B35F9CC94DB2BC7B43BB59 /* CoinRankViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A1E2AE3DC240D5B785E /* CoinRankViewController.swift */; }; 11B35F9E1AF528B31C6F383C /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B352E52084020190C21D8C /* InputView.swift */; }; 11B35F9F489F4B358FCCE893 /* MarkdownParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3543968337A40168D3EB0 /* MarkdownParser.swift */; }; 11B35FA1970606C12E57C2EA /* ChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AFE2C95FF73F75652D8 /* ChartView.swift */; }; 11B35FA298822DABDB1CD109 /* PreSendViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357FD9D760D9671A3DF24 /* PreSendViewModel.swift */; }; - 11B35FA3A00690573A482BAC /* CoinRankViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A1E2AE3DC240D5B785E /* CoinRankViewController.swift */; }; 11B35FA6F9EE876BD65E9AD6 /* LaunchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3595BAA550B6BEC8C3F72 /* LaunchScreen.swift */; }; 11B35FA70EB07440E1576A56 /* RowButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BAA4EA85B4A3A173498 /* RowButtonStyle.swift */; }; 11B35FAB3263E489CB9017FC /* AddTokenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356D5A5F32E88FEC7629D /* AddTokenViewController.swift */; }; @@ -1498,76 +1426,51 @@ 11B35FE0809AC8A716C41427 /* PrimaryButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35968D12AAAC828AFE955 /* PrimaryButtonStyle.swift */; }; 11B35FE603192CF3195115D0 /* LanguageSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35920D0AD623C5E4A4460 /* LanguageSettingsViewModel.swift */; }; 11B35FE8D60BFF31C3104484 /* SwitchAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350BC3E707879846AC0AA /* SwitchAccountViewModel.swift */; }; - 11B35FEB268E7C6B085B56C9 /* MarketOverviewTopPairsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AB1D0CE5D8ECE7DDF65 /* MarketOverviewTopPairsViewModel.swift */; }; 11B35FEC7AA2A8887FCF0AE6 /* StatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359980AA45D6B44151D7A /* StatManager.swift */; }; 11B35FF02BADC6D832836C44 /* EvmPrivateKeyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353262E45560C91FD6B65 /* EvmPrivateKeyViewModel.swift */; }; 11B35FF072E32C5D4028D0F6 /* TextInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35968F5DE9FDA6EC26FCD /* TextInputCell.swift */; }; 11B35FF10EF7FC47869EF295 /* CexWithdrawViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B2465CB748311AF03D5 /* CexWithdrawViewModel.swift */; }; - 11B35FF14C4B775E570375EC /* MarketTopPairsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359715B07FD5316D72A07 /* MarketTopPairsViewModel.swift */; }; 11B35FF1D956D812F815FA86 /* NftImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3522A9A7774977CF39A1D /* NftImageView.swift */; }; 11B35FF65FCE441A69822E1C /* InputPrefixWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35743158763BD8E336770 /* InputPrefixWrapperView.swift */; }; 11B35FF681C01782693B3C4A /* SendEvmConfirmationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354950B1534AD045FDA3A /* SendEvmConfirmationViewController.swift */; }; - 11B35FF6D36153F372C16C32 /* MarketWatchlistViewModelOld.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3566FE007887C3528583C /* MarketWatchlistViewModelOld.swift */; }; 11B35FF84A61FFBEC01CE15E /* BlockchainTokensViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B350B29B000CD809F81228 /* BlockchainTokensViewModel.swift */; }; 11B35FFC8C3E4CF638397650 /* UnlockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D36E5D47264AE07D729 /* UnlockView.swift */; }; 11B35FFD159D864F6D914F08 /* AppearanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357511F8F17D8221B64E2 /* AppearanceView.swift */; }; 11B35FFE6FBDA949184E2BF2 /* AmountInputViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F2BE131B969BBEABDB9 /* AmountInputViewModel.swift */; }; 1A564001701A1E77AF7A651B /* BalanceErrorModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564AB0B646F7A92DD188F2 /* BalanceErrorModule.swift */; }; - 1A5640051485E3419FE674F1 /* MarketTopPlatformsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564995DE20E52E8E0F1E6A /* MarketTopPlatformsViewModel.swift */; }; - 1A56402D725D6AB0C4149066 /* MarketTopPlatformsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564995DE20E52E8E0F1E6A /* MarketTopPlatformsViewModel.swift */; }; 1A564032D3C011BCAA7D44A8 /* DeepLinkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564DEB9782FF55EFFD8CCA /* DeepLinkService.swift */; }; 1A56404471A7270782D6619F /* AppVersion_v_0_20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646C5FEE5A60A658B0180 /* AppVersion_v_0_20.swift */; }; - 1A564047000F9270ABC4AEC1 /* MarketTopPlatformsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C4DB4A57CCF2C5EFB78 /* MarketTopPlatformsViewController.swift */; }; - 1A56405220ED225C0B973A7F /* MarketOverviewTopCoinsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D661F3AE561D7FE9FAA /* MarketOverviewTopCoinsService.swift */; }; - 1A56405536E22BFF69EE9593 /* MarketOverviewTopCoinsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5640B4F6298D9F326C5EDE /* MarketOverviewTopCoinsViewModel.swift */; }; 1A564058DB366C810AC3C47A /* TitledHighlightedDescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CB28708314AE0A69424 /* TitledHighlightedDescriptionView.swift */; }; - 1A56405B48462C0750A47ECA /* MarketOverviewTopCoinsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646218714BA81DE9B5631 /* MarketOverviewTopCoinsDataSource.swift */; }; 1A56405DB1540DEC70FD5CFA /* HighlightedDescriptionBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BCC9DD29DB5455669A5 /* HighlightedDescriptionBaseView.swift */; }; 1A56408B1A402BC99846F141 /* ZcashAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5642E923141415CCFC9167 /* ZcashAddressParserItem.swift */; }; - 1A5640D097E24A155C1F2E56 /* MarketOverviewCategoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5645B1C5FD344967B1F4B7 /* MarketOverviewCategoryCell.swift */; }; 1A5640D6FDF86EDB54213F9B /* DeepLinkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564580B3F739DAC59C623F /* DeepLinkManager.swift */; }; 1A5640DE72AC306799695F48 /* TopPlatformMarketCapFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A1B86DF22E86F0BB442 /* TopPlatformMarketCapFetcher.swift */; }; - 1A56412970FD129426474522 /* MarketOverviewTopPlatformsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564B44985D1169593F202C /* MarketOverviewTopPlatformsDataSource.swift */; }; 1A56413DFF5B9A8E3F2A5EA6 /* ReleaseNotesMarkdownConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56432704A2E7A9BE78497B /* ReleaseNotesMarkdownConfig.swift */; }; 1A56415A4BB89B9156C6442D /* Decimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D5E55767404ED6C88E0 /* Decimal.swift */; }; 1A564168590F031AA453E1D1 /* BalanceErrorModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564AB0B646F7A92DD188F2 /* BalanceErrorModule.swift */; }; 1A56416B9DC6DA281AD34575 /* AdapterState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5647ACB8A65C250F62E07D /* AdapterState.swift */; }; - 1A564176DEB9ED375113DA3B /* MarketTopPlatformsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56459D85D4859D8A0F4D5A /* MarketTopPlatformsModule.swift */; }; - 1A56417AE8B0F2513FC009A9 /* MarketListTopPlatformDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C5CC7EC339C3113869D /* MarketListTopPlatformDecorator.swift */; }; - 1A56418183EC6CB602873B51 /* MarketListTopPlatformDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C5CC7EC339C3113869D /* MarketListTopPlatformDecorator.swift */; }; 1A5641C097AAD5FC9D35F9EE /* TransactionDataSortMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564E6A6B7E18C287A1D77D /* TransactionDataSortMode.swift */; }; 1A5641F1A0F4E8FC6555D480 /* BtcBlockchainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646B6231F2C52F27526F7 /* BtcBlockchainManager.swift */; }; - 1A56422231460374E3830E56 /* MarketListWatchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564555A67E4DC1DC935A04 /* MarketListWatchViewModel.swift */; }; - 1A5642348A701CF7CF5CD805 /* MarketOverviewGlobalDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5647FA18CC69113ECB6581 /* MarketOverviewGlobalDataSource.swift */; }; - 1A564240E0BC3E93EDB3BA22 /* MarketNftTopCollectionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D12426BCA027C67377E /* MarketNftTopCollectionsService.swift */; }; 1A56424B5327D4ADFD728B0B /* BlockchainSettingRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C46FB773A67E29D9D32 /* BlockchainSettingRecord.swift */; }; 1A56427D35F4EDC473A732E7 /* ReadMoreTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56485B094980B68B0A86AE /* ReadMoreTextCell.swift */; }; - 1A56427F500823630D07E75D /* MarketNftTopCollectionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649E41FE690AF0A712426 /* MarketNftTopCollectionsViewModel.swift */; }; 1A5642F3BA1892109A596B61 /* MarkdownContentProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56417C27A95B429D9F2912 /* MarkdownContentProvider.swift */; }; 1A5642F3C5C414F65A3CC59D /* TitledHighlightedDescriptionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56444EB2F32DB662981653 /* TitledHighlightedDescriptionCell.swift */; }; - 1A564335057D41EECDC8021B /* MarketOverviewTopCoinsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D661F3AE561D7FE9FAA /* MarketOverviewTopCoinsService.swift */; }; 1A5643651979E1907BE1B12C /* BlockchainSettingRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C46FB773A67E29D9D32 /* BlockchainSettingRecord.swift */; }; 1A5643813B0713460096F6D1 /* AppVersionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56446CCB15D32581396A59 /* AppVersionRecord.swift */; }; 1A5643A263F288A4E83409FA /* BalanceErrorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564702FB246F315983743E /* BalanceErrorViewModel.swift */; }; - 1A5643B0422BC87461CC25C5 /* MarketOverviewTopPlatformsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564B44985D1169593F202C /* MarketOverviewTopPlatformsDataSource.swift */; }; 1A5643BCA38A75A63D57F1AB /* SendEthereumErrorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564920282E84A6E7EE05EB /* SendEthereumErrorCell.swift */; }; 1A5643BCDAD7CB0230CBB513 /* GradientClippingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C4B0D13BC7214419A3E /* GradientClippingView.swift */; }; 1A5643C5A8BBFD6F2DC8C734 /* BtcRestoreMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BE241BFC5DD59D0FB7C /* BtcRestoreMode.swift */; }; 1A5643C73BEDA01E4E378BEF /* ZcashAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5642E923141415CCFC9167 /* ZcashAddressParserItem.swift */; }; - 1A5643CB57594E84707686A3 /* MarketOverviewGlobalDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5647FA18CC69113ECB6581 /* MarketOverviewGlobalDataSource.swift */; }; 1A5643CFF5657C9C6B7DBA19 /* ThemeSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EA6F1CCDF88F78351F8 /* ThemeSearchViewController.swift */; }; 1A5643D323BAB0B8B45A9038 /* PrivacyPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CE10FD5FEC14EF38BD8 /* PrivacyPolicyViewController.swift */; }; 1A5643D7C72CDCB87E3D5F17 /* SendTransactionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56422C196B48931CDE1445 /* SendTransactionError.swift */; }; - 1A5643E2C1AB8F24605342A0 /* MarketListNftCollectionDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CC5878BF33B8CE1F339 /* MarketListNftCollectionDecorator.swift */; }; 1A564406716193E4A2D9075F /* ReachabilityViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564814721244F4D4D87557 /* ReachabilityViewModel.swift */; }; 1A56440AD78BD32AEAE2A2EA /* PlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5644A21F9FEC4E2A7B0860 /* PlaceholderView.swift */; }; 1A56441AD76BA80CB74902CB /* TraitCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5648911028181BB1462CFE /* TraitCell.swift */; }; 1A5644271F4CD209136352EE /* FilterHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564B1C051AF2C87C670563 /* FilterHeaderView.swift */; }; - 1A56443EA3671FA2A40F1F7E /* TopPlatformModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BDA5600859626D99BB4 /* TopPlatformModule.swift */; }; 1A56444313F5FB0DE9B06BE4 /* PrivacyPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CE10FD5FEC14EF38BD8 /* PrivacyPolicyViewController.swift */; }; - 1A56444C8342498C892E931E /* MarketNftTopCollectionsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564E5282C3C22DA85141AF /* MarketNftTopCollectionsModule.swift */; }; 1A5644CF2BEC2E7C6227BDC7 /* AppStatusModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56404C1C16B85434117DB7 /* AppStatusModule.swift */; }; - 1A5644FA9A9599F94EE16916 /* MarketNftTopCollectionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649E41FE690AF0A712426 /* MarketNftTopCollectionsViewModel.swift */; }; 1A5644FE2885F71299CC66EA /* PlaceholderViewModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CF35E7A07E96B704ADA /* PlaceholderViewModule.swift */; }; 1A564504E164177DD6EECFBA /* BalanceErrorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646B5D68A302515565030 /* BalanceErrorService.swift */; }; 1A564512989CEBC48ABCB94E /* ConvertedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A6A5C4F3080690AE93F /* ConvertedError.swift */; }; @@ -1576,15 +1479,11 @@ 1A5645335BEED7A26D53A6B9 /* AddressUri.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649C6FFC694CD18A8B39A /* AddressUri.swift */; }; 1A56454D8C03B7B1141635DA /* EnabledWallet_v_0_13.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A55E5866D6081EA6F69 /* EnabledWallet_v_0_13.swift */; }; 1A564564359185321F81541D /* TitledHighlightedDescriptionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56444EB2F32DB662981653 /* TitledHighlightedDescriptionCell.swift */; }; - 1A564586DCCE6E87784B9E6E /* MarketListWatchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564555A67E4DC1DC935A04 /* MarketListWatchViewModel.swift */; }; - 1A5645A90CB5AAEF02745AC7 /* MarketNftTopCollectionsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564E5282C3C22DA85141AF /* MarketNftTopCollectionsModule.swift */; }; 1A5645BF7E9F7DF6B0C8912C /* PlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5644A21F9FEC4E2A7B0860 /* PlaceholderView.swift */; }; 1A5645C7334EED7FF57FFD47 /* DashAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EA8CD67010BFFC57AAB /* DashAddressParserItem.swift */; }; - 1A5645CA87E32639CEE6681F /* MarketOverviewGlobalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649C48B3AABC56D2512ED /* MarketOverviewGlobalViewModel.swift */; }; 1A5645D6AC7D344E6D3D0CAF /* AppVersion_v_0_20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646C5FEE5A60A658B0180 /* AppVersion_v_0_20.swift */; }; 1A5645DA5F609D469D12A6E1 /* AppVersionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56446CCB15D32581396A59 /* AppVersionRecord.swift */; }; 1A5645DE1329BC81C1A9B711 /* BtcBlockchainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646B6231F2C52F27526F7 /* BtcBlockchainManager.swift */; }; - 1A5646322B606C56DFFA324A /* NftCollectionsMultiSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5643A672A508BC4CBCABDD /* NftCollectionsMultiSortHeaderViewModel.swift */; }; 1A56463AB918839385E8CDBD /* BlockchainSettingsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56443BF752CB6537E45F5A /* BlockchainSettingsStorage.swift */; }; 1A56463FADAB4646BA106A5D /* TopPlatformMarketCapFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A1B86DF22E86F0BB442 /* TopPlatformMarketCapFetcher.swift */; }; 1A56464440899E3299F79D32 /* JailbreakService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56469A2F3EAAEDECFB4034 /* JailbreakService.swift */; }; @@ -1593,22 +1492,15 @@ 1A564665243CEEBF646D1328 /* ConvertedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A6A5C4F3080690AE93F /* ConvertedError.swift */; }; 1A564699CFB7CCE8BD3E5245 /* AppVersionStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564AFF2709E27114985A8D /* AppVersionStorage.swift */; }; 1A5646C3220E1735309D2927 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564B7C35C5B235D2BBAC2C /* AppVersion.swift */; }; - 1A5646E52D8DFADAA5ACFCAD /* TopPlatformsMultiSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D8F8A8A63BC9BEAAD56 /* TopPlatformsMultiSortHeaderViewModel.swift */; }; 1A5646E67996AB355694A35E /* EnabledWallet_v_0_13.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A55E5866D6081EA6F69 /* EnabledWallet_v_0_13.swift */; }; 1A5646F57C3677EBC462673C /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56489DE231CDDCA75CAEB3 /* AppError.swift */; }; 1A5647072B937BE4B69FFA1D /* SendEthereumErrorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564920282E84A6E7EE05EB /* SendEthereumErrorCell.swift */; }; - 1A56470F4D18CCC43B85DEB3 /* MarketOverviewCategoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564ADD13E597F423249CA3 /* MarketOverviewCategoryViewModel.swift */; }; 1A56475828E9121D78E02D67 /* BitcoinCashAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BF724C69C237E309C07 /* BitcoinCashAdapter.swift */; }; 1A564776B26828610A295FDF /* DashAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EA8CD67010BFFC57AAB /* DashAddressParserItem.swift */; }; - 1A5647BB75003E8292C8144B /* BaseMarketOverviewTopListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5644E4694DBB0E6E0B10CC /* BaseMarketOverviewTopListDataSource.swift */; }; 1A5647EF2A5B8141F0BE4320 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56447C12D91108517ED217 /* UIDevice.swift */; }; 1A56481FC0EAFA9FC32E1E21 /* ScanQrViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A144576DB93334E1682 /* ScanQrViewController.swift */; }; 1A56483DCD5E1942AFAC0A1C /* ReachabilityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D8AD6D160F27C021F48 /* ReachabilityService.swift */; }; - 1A5648701B55E09FD8E4585D /* MarketOverviewTopPlatformsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56477F6FC71270AD53A3AE /* MarketOverviewTopPlatformsViewModel.swift */; }; - 1A5648AB801E8DAA9B3D288E /* MarketOverviewGlobalService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EDF0FD6A1D1575D1EFB /* MarketOverviewGlobalService.swift */; }; 1A5648ACB0A6B11E0E39A1B0 /* AppVersionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5641CDB00EF52E18BF70F3 /* AppVersionManager.swift */; }; - 1A5648ACF2A5B2F7420DA5F6 /* MarketTopPlatformsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56459D85D4859D8A0F4D5A /* MarketTopPlatformsModule.swift */; }; - 1A5648B10B34B402167EEA84 /* TopPlatformService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649C0BD100768C726B4FB /* TopPlatformService.swift */; }; 1A5648B6D95710939690F22A /* PerformanceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5641E505FE004F601943C4 /* PerformanceTableViewCell.swift */; }; 1A5648C0787EBA8CDCB6F761 /* ReachabilityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D8AD6D160F27C021F48 /* ReachabilityService.swift */; }; 1A5648D075682B17EFE9CBB6 /* AddressUri.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649C6FFC694CD18A8B39A /* AddressUri.swift */; }; @@ -1620,19 +1512,14 @@ 1A564977D009E610D8D194AE /* TitledHighlightedDescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CB28708314AE0A69424 /* TitledHighlightedDescriptionView.swift */; }; 1A56498C73C42F16A2D96A8D /* HighlightedDescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564730E8F235240D62124B /* HighlightedDescriptionView.swift */; }; 1A5649926B0064083045BEEB /* BalanceErrorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646B5D68A302515565030 /* BalanceErrorService.swift */; }; - 1A56499414D2E3BBFF260D14 /* MarketNftTopCollectionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D12426BCA027C67377E /* MarketNftTopCollectionsService.swift */; }; - 1A5649ADA72E39CE24BB64FC /* MarketOverviewCategoryDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A6D161EAD22626332C1 /* MarketOverviewCategoryDataSource.swift */; }; 1A5649CEE6EFCC06A10F69CF /* TraitCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5648911028181BB1462CFE /* TraitCell.swift */; }; 1A5649F72A0116C66DCBA153 /* AppVersionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5641CDB00EF52E18BF70F3 /* AppVersionManager.swift */; }; 1A564A1CA02CF6F6DC37B50A /* AcademyMarkdownConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564215DD6F0D54C1F6C4F7 /* AcademyMarkdownConfig.swift */; }; 1A564A24327DB692A068D909 /* FilterHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564293D88587642800717B /* FilterHeaderCell.swift */; }; 1A564A2B23326B3057C37962 /* AdapterError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564504718E7D19F379A9F7 /* AdapterError.swift */; }; 1A564A2FCE3C764029FECB7B /* GradientClippingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C4B0D13BC7214419A3E /* GradientClippingView.swift */; }; - 1A564A45605FA993F9680646 /* MarketOverviewTopCoinsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5640B4F6298D9F326C5EDE /* MarketOverviewTopCoinsViewModel.swift */; }; - 1A564A4CF522A7A959482AA6 /* MarketOverviewGlobalService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EDF0FD6A1D1575D1EFB /* MarketOverviewGlobalService.swift */; }; 1A564A7CB794B4367A87C5E2 /* FilterHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564293D88587642800717B /* FilterHeaderCell.swift */; }; 1A564A905233BD9AB9241916 /* ButtonState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5642E9B9E5592E04373C16 /* ButtonState.swift */; }; - 1A564A9E6FF0EB1C6F2AA102 /* MarketTopPlatformsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564C4DB4A57CCF2C5EFB78 /* MarketTopPlatformsViewController.swift */; }; 1A564AB50152BF82514BAC3C /* HighlightedDescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564730E8F235240D62124B /* HighlightedDescriptionView.swift */; }; 1A564AB8471E098F68FDB9D7 /* BinanceAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564872B7C5F76D8CE55A8B /* BinanceAddressParserItem.swift */; }; 1A564ABF3417C13718D78F57 /* ThemeSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EA6F1CCDF88F78351F8 /* ThemeSearchViewController.swift */; }; @@ -1644,49 +1531,32 @@ 1A564BA5366D4F0B921F5EE8 /* ThemeActionSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564E86CCEAD0F9956664D4 /* ThemeActionSheetController.swift */; }; 1A564BAB51E12A8F37D870B5 /* PerformanceSideCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564B73ABBEFC58A13D501E /* PerformanceSideCollectionViewCell.swift */; }; 1A564BB34D0EAA2E8BE8B498 /* DeepLinkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564580B3F739DAC59C623F /* DeepLinkManager.swift */; }; - 1A564BC0945C7CA8330A604E /* MarketNftTopCollectionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5641A724199908970CFB54 /* MarketNftTopCollectionsViewController.swift */; }; - 1A564BC7CE38935CD443C235 /* MarketOverviewTopCoinsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646218714BA81DE9B5631 /* MarketOverviewTopCoinsDataSource.swift */; }; 1A564BC84E6A4F836994ABD3 /* AdapterError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564504718E7D19F379A9F7 /* AdapterError.swift */; }; 1A564C10B9782D53375736C8 /* ReleaseNotesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5644074A3ACB1DFB63FF92 /* ReleaseNotesService.swift */; }; 1A564C11B7785DCEA2472065 /* BitcoinCashAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BF724C69C237E309C07 /* BitcoinCashAdapter.swift */; }; - 1A564C13834A2EE853542795 /* MarketListNftCollectionDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CC5878BF33B8CE1F339 /* MarketListNftCollectionDecorator.swift */; }; - 1A564C1395A1264F1A9B3AB5 /* TopPlatformModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BDA5600859626D99BB4 /* TopPlatformModule.swift */; }; - 1A564C2E1B66C2C508F8327D /* MarketOverviewTopPlatformsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56477F6FC71270AD53A3AE /* MarketOverviewTopPlatformsViewModel.swift */; }; - 1A564C6CCA15813506F20561 /* MarketOverviewCategoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564ADD13E597F423249CA3 /* MarketOverviewCategoryViewModel.swift */; }; 1A564C756284485E93C0F78D /* AdapterState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5647ACB8A65C250F62E07D /* AdapterState.swift */; }; 1A564CA2A36B55AC41BBA0F4 /* SendTransactionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56422C196B48931CDE1445 /* SendTransactionError.swift */; }; 1A564CBB4708B7DAC6D6A2AD /* BlockchainSettingsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56443BF752CB6537E45F5A /* BlockchainSettingsStorage.swift */; }; - 1A564CC4790F0CED826C131F /* MarketOverviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564206FEC56546760B9BEA /* MarketOverviewViewModel.swift */; }; 1A564CFD8F22A2F5FDB346EA /* JailbreakService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56469A2F3EAAEDECFB4034 /* JailbreakService.swift */; }; 1A564D02348C91416FD011FC /* TraitsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564FF31C5E879781A2D5E0 /* TraitsCell.swift */; }; 1A564D209D3AFA40F808C8FB /* PerformanceContentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646483957D74946973BEE /* PerformanceContentCollectionViewCell.swift */; }; 1A564D2917CF5C38C84C031B /* BitcoinBaseAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56450DA6DF97C9E1FFE987 /* BitcoinBaseAdapter.swift */; }; 1A564D3DB55C8CB8B5AED664 /* BalanceErrorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564702FB246F315983743E /* BalanceErrorViewModel.swift */; }; - 1A564D4581F280245579C9DF /* BaseMarketOverviewTopListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5644E4694DBB0E6E0B10CC /* BaseMarketOverviewTopListDataSource.swift */; }; 1A564D53F049C4784CAC814D /* BtcRestoreMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BE241BFC5DD59D0FB7C /* BtcRestoreMode.swift */; }; 1A564D69A570D801AF59FF58 /* ReadMoreTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56485B094980B68B0A86AE /* ReadMoreTextCell.swift */; }; 1A564D81725888B31D56F389 /* PerformanceContentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5646483957D74946973BEE /* PerformanceContentCollectionViewCell.swift */; }; 1A564D86E3D7E200D9B81592 /* AppVersionStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564AFF2709E27114985A8D /* AppVersionStorage.swift */; }; 1A564DBDAA43925DC8E39164 /* TraitsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564FF31C5E879781A2D5E0 /* TraitsCell.swift */; }; 1A564DC4E55C1BE1C4D4CDA9 /* HighlightedDescriptionBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564BCC9DD29DB5455669A5 /* HighlightedDescriptionBaseView.swift */; }; - 1A564DCC65AA9EADE56F2B7F /* MarketNftTopCollectionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5641A724199908970CFB54 /* MarketNftTopCollectionsViewController.swift */; }; - 1A564DFD9A3B16E7DA518F67 /* NftCollectionsMultiSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5643A672A508BC4CBCABDD /* NftCollectionsMultiSortHeaderViewModel.swift */; }; - 1A564E08B4F6C5B1CDB121F6 /* MarketTopPlatformsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5648E7534C2E7F16C4A2D4 /* MarketTopPlatformsService.swift */; }; 1A564E09FB049006167E033B /* PerformanceSideCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564B73ABBEFC58A13D501E /* PerformanceSideCollectionViewCell.swift */; }; 1A564E0B7DB0060B9600FCB1 /* BalanceErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CE56CEC73B78C9DB6B5 /* BalanceErrorViewController.swift */; }; - 1A564E1912184BFC886548D9 /* MarketOverviewCategoryDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A6D161EAD22626332C1 /* MarketOverviewCategoryDataSource.swift */; }; - 1A564E2897197EB14584A62E /* MarketOverviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564206FEC56546760B9BEA /* MarketOverviewViewModel.swift */; }; 1A564E69BA99DF8CD4562902 /* PlaceholderViewModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564CF35E7A07E96B704ADA /* PlaceholderViewModule.swift */; }; 1A564E8CA0CFBE8B1E232B60 /* PerformanceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5641E505FE004F601943C4 /* PerformanceTableViewCell.swift */; }; - 1A564EBD7F2BB47C7C209EC5 /* TopPlatformsMultiSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D8F8A8A63BC9BEAAD56 /* TopPlatformsMultiSortHeaderViewModel.swift */; }; 1A564EDBD3E4B37299E199B7 /* AppStatusModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56404C1C16B85434117DB7 /* AppStatusModule.swift */; }; 1A564EDED3DA0C27A223C54A /* BasePerformanceCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D7B1F36B1C4AB4CBF3A /* BasePerformanceCollectionViewCell.swift */; }; 1A564EE727CD892E7F2E5715 /* ScanQrViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564A144576DB93334E1682 /* ScanQrViewController.swift */; }; - 1A564EF252E8C535BEB0548B /* MarketTopPlatformsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5648E7534C2E7F16C4A2D4 /* MarketTopPlatformsService.swift */; }; 1A564F382602A283C370E7FB /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56489DE231CDDCA75CAEB3 /* AppError.swift */; }; - 1A564F3C50FC28F2AF4AF4ED /* MarketOverviewGlobalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649C48B3AABC56D2512ED /* MarketOverviewGlobalViewModel.swift */; }; 1A564F73B7FE144D39DEA34F /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56447C12D91108517ED217 /* UIDevice.swift */; }; - 1A564FC84916FF6D6224FB33 /* MarketOverviewCategoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5645B1C5FD344967B1F4B7 /* MarketOverviewCategoryCell.swift */; }; 1A564FEF3AEC87712186DD28 /* DeepLinkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564DEB9782FF55EFFD8CCA /* DeepLinkService.swift */; }; 1A564FFA4566A5019E744E8E /* TransactionDataSortMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564E6A6B7E18C287A1D77D /* TransactionDataSortMode.swift */; }; 2FA5D01A5570C6DE5D07E2C4 /* EvmFeeViewItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA5DCD7797C13645F3D5F8A /* EvmFeeViewItemFactory.swift */; }; @@ -1831,20 +1701,6 @@ 2FA5DFD5AFFA720FA28CCD6A /* TransactionInfoViewItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA5D299198FEF01FB5D06DE /* TransactionInfoViewItemFactory.swift */; }; 3A73FC69258B1AD100FE4D34 /* MarketModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA3173853A16B2433AEC0 /* MarketModule.swift */; }; 3A73FC6A258B1AD200FE4D34 /* MarketModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA3173853A16B2433AEC0 /* MarketModule.swift */; }; - 3A73FC74258B1ADA00FE4D34 /* MarketViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8FDCCC09B609C7D0FEA /* MarketViewController.swift */; }; - 3A73FC75258B1ADB00FE4D34 /* MarketViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8FDCCC09B609C7D0FEA /* MarketViewController.swift */; }; - 3A73FC78258B1AE500FE4D34 /* MarketViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA9DFF1F23B0B8A8CEAD /* MarketViewModel.swift */; }; - 3A73FC7A258B1AE500FE4D34 /* MarketViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA9DFF1F23B0B8A8CEAD /* MarketViewModel.swift */; }; - 3A73FC99258B1AF600FE4D34 /* MarketWatchlistViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA1B62A6A1A278BE06AA /* MarketWatchlistViewController.swift */; }; - 3A73FC9B258B1AF700FE4D34 /* MarketWatchlistModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7D27615D192FBC5486E /* MarketWatchlistModule.swift */; }; - 3A73FC9C258B1AF700FE4D34 /* MarketWatchlistViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA1B62A6A1A278BE06AA /* MarketWatchlistViewController.swift */; }; - 3A73FC9E258B1AF700FE4D34 /* MarketWatchlistModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7D27615D192FBC5486E /* MarketWatchlistModule.swift */; }; - 3A73FCAA258B1AFC00FE4D34 /* MarketMetricView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA50A504CFA74CA19A415 /* MarketMetricView.swift */; }; - 3A73FCAD258B1AFC00FE4D34 /* GradientPercentCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA3930D3CB65CC545658 /* GradientPercentCircle.swift */; }; - 3A73FCAE258B1AFD00FE4D34 /* MarketMetricView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA50A504CFA74CA19A415 /* MarketMetricView.swift */; }; - 3A73FCB1258B1AFD00FE4D34 /* GradientPercentCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA3930D3CB65CC545658 /* GradientPercentCircle.swift */; }; - 3AB682BE25BADD97002197A5 /* MarketOverviewModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB682BC25BADD97002197A5 /* MarketOverviewModule.swift */; }; - 3AB682BF25BADD97002197A5 /* MarketOverviewModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB682BC25BADD97002197A5 /* MarketOverviewModule.swift */; }; 3AF9F61A253EF555000626A8 /* ZcashTransactionPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9F617253EF555000626A8 /* ZcashTransactionPool.swift */; }; 3AF9F61B253EF555000626A8 /* ZcashTransactionPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9F617253EF555000626A8 /* ZcashTransactionPool.swift */; }; 3AF9F61D253EF555000626A8 /* ZcashAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9F618253EF555000626A8 /* ZcashAdapter.swift */; }; @@ -1861,14 +1717,10 @@ 5039F973269C5A9B004711B8 /* ReleaseNotesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5039F971269C5A9A004711B8 /* ReleaseNotesViewController.swift */; }; 5046E671259C491000A941E5 /* InfoSeparatorHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA6FB0AF97333CD9D007F /* InfoSeparatorHeaderView.swift */; }; 5046E672259C491100A941E5 /* InfoSeparatorHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA6FB0AF97333CD9D007F /* InfoSeparatorHeaderView.swift */; }; - 505E7F742897C6DA00229BF2 /* TopPlatformService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5649C0BD100768C726B4FB /* TopPlatformService.swift */; }; 50701ACE25B041E600EDE51B /* JailbreakTestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D2011D7A4E80B2B7B92 /* JailbreakTestManager.swift */; }; 50701ACF25B041E600EDE51B /* JailbreakTestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A564D2011D7A4E80B2B7B92 /* JailbreakTestManager.swift */; }; - 58AAA004F244AFFC352ADCEF /* MarketSingleSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA15F4FA7B9EC091EDFF3 /* MarketSingleSortHeaderView.swift */; }; 58AAA0444AD1508917D349CF /* UniswapSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFF6E494F623AD62AF95 /* UniswapSettingsService.swift */; }; 58AAA0642CB9B7B19C6235B5 /* AmountDecimalParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAF740AE2BEBD7CEBD563 /* AmountDecimalParser.swift */; }; - 58AAA07B54F11F0DF5E3E876 /* MarketPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA263DAB58FD63E6A9351 /* MarketPostViewController.swift */; }; - 58AAA08E3204C7E7326E1DF9 /* MarketTvlSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA78BB269FEBB430092A3 /* MarketTvlSortHeaderViewModel.swift */; }; 58AAA097F8417B30693547FE /* CoinPageMarkdownParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA444C885BCC354F1B7B3 /* CoinPageMarkdownParser.swift */; }; 58AAA0BEEC3EF61DCB80C6BA /* DebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA6EA2DAD95D2CB417FD /* DebugViewController.swift */; }; 58AAA0C0DB5C901FE58F5F9B /* FeeSliderWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAC2D03916C80C8DC5FE5 /* FeeSliderWrapper.swift */; }; @@ -1881,30 +1733,22 @@ 58AAA126020F429D94D77A76 /* OneInchSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA75A0580C45CC08D89E8 /* OneInchSettingsService.swift */; }; 58AAA1283FC7F83F62FC5961 /* FeeSliderValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA3C555FBFB5423CCF8E0 /* FeeSliderValueView.swift */; }; 58AAA13C1DC5FA79BCA1D732 /* UdnAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9A4761030BE9F60C85E /* UdnAddressParserItem.swift */; }; - 58AAA153DF6764D7FEA99D63 /* MarketGlobalTvlMetricService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAADBB7B760C189AD6032F /* MarketGlobalTvlMetricService.swift */; }; 58AAA15A6F863CD3940FEBCC /* CoinCardModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8AD6794AD2AAF462B7B /* CoinCardModule.swift */; }; 58AAA1721028D6504074A158 /* CoinSelectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9BBAB97C2D21A83956C /* CoinSelectViewController.swift */; }; 58AAA187A094370FA7CD2BDD /* InfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA83833C970A2DC467715 /* InfoViewController.swift */; }; 58AAA188EBE3E1CC463D8D9F /* SwapAllowanceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7C8532511E4BCD9C8D9 /* SwapAllowanceCell.swift */; }; 58AAA1AAD335F236D130FCBB /* SwapConfirmationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB39CAE1453B9ED024E4 /* SwapConfirmationModule.swift */; }; - 58AAA1B716FCD40947F4F95C /* MarketOverviewHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA2521E8F8845D96AB865 /* MarketOverviewHeaderCell.swift */; }; 58AAA1D61188628A61F1E047 /* DebugInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA16C7E337511638808E5 /* DebugInteractor.swift */; }; 58AAA1EC97682F9347B8CA32 /* ChartModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA5C1F206B755B477A30B /* ChartModule.swift */; }; 58AAA203CEB400A883379822 /* DownloadService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA2B7F82F42442ED27A67 /* DownloadService.swift */; }; 58AAA2100166FDFB110FA6D0 /* ChartConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9D5D29115C5F435CF1B /* ChartConfiguration.swift */; }; - 58AAA2494D41B33DC091A3E6 /* MarketPostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA657E30EBD52A5E06ACF /* MarketPostService.swift */; }; - 58AAA25AF71DF84F42A27157 /* MarketPostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA11651E3CE29A461BF42 /* MarketPostViewModel.swift */; }; 58AAA27FE69D5AF00F771C7F /* Global.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8B7E47FF3B010851E58 /* Global.swift */; }; 58AAA289FEAE983739189B8D /* RecipientAddressViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA19E66FCA0575AE33FAA /* RecipientAddressViewModel.swift */; }; - 58AAA2960B54658E2614D72E /* MarketGlobalMetricService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7B3EA0C8B9FDEC41837 /* MarketGlobalMetricService.swift */; }; 58AAA29A7E913ABAB6592FD7 /* SwapCoinCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA80C6D2024281A5FA3E5 /* SwapCoinCardViewModel.swift */; }; 58AAA29F80AC65D37BD1D289 /* CoinSelectViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB692B7C326319D186E4 /* CoinSelectViewModel.swift */; }; 58AAA2CEB9DB7E34921D7778 /* SwapDeadlineViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFF25BF263B5EC4188F7 /* SwapDeadlineViewModel.swift */; }; 58AAA2EBAFC1C443C48BA857 /* CoinChartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA55A4A6A97C25F84034F /* CoinChartFactory.swift */; }; - 58AAA31D8AD811C0C5434426 /* MarketPostModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA42A6EB5242006547A92 /* MarketPostModule.swift */; }; - 58AAA331B4A743D9183F8449 /* MarketListTvlDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9B26F62DB74FF3830D5 /* MarketListTvlDecorator.swift */; }; 58AAA34F0F6195DF86596A41 /* ChartConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9D5D29115C5F435CF1B /* ChartConfiguration.swift */; }; - 58AAA35AF4F4454E0E9C7C60 /* MarketSingleSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA51AD262FBDC3D69EEF8 /* MarketSingleSortHeaderViewModel.swift */; }; 58AAA3692F9336D6AD79367F /* StepBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA422A0530C0C07E19F2F /* StepBadgeView.swift */; }; 58AAA3762D78142A83A22F50 /* SwapViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAEB2257174A64DE5E51B /* SwapViewModel.swift */; }; 58AAA393DF93EFFA5047589B /* FeeSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA24B6EB7103CB072A53D /* FeeSlider.swift */; }; @@ -1913,12 +1757,10 @@ 58AAA3A6458CB87F359F6366 /* SwapConfirmationAmountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA5BF9EE200DAA24AD42A /* SwapConfirmationAmountCell.swift */; }; 58AAA3BE2D0DEF53CE6CEE97 /* EvmKitManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAC5B00009B199A687EF3 /* EvmKitManager.swift */; }; 58AAA3F0AFD0D0F5FCD24DEF /* SelectorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAE153E9683CB79DCF857 /* SelectorButton.swift */; }; - 58AAA3FE5DE72D3CEFFE4399 /* MarketPostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA657E30EBD52A5E06ACF /* MarketPostService.swift */; }; 58AAA4109DE36F8934808DE0 /* MarketGlobalModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7D7F06F7C044DF9CE0A /* MarketGlobalModule.swift */; }; 58AAA410C9996BA929E3CEEF /* InfoModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAD7AC450FEF913E5417F /* InfoModule.swift */; }; 58AAA415B26725FEF4A1128D /* DoubleSpendInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA72BD42697A894C2383C /* DoubleSpendInfoViewController.swift */; }; 58AAA431B5939F7961B65CCF /* CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB126AA1B83DD40C426F /* CALayer.swift */; }; - 58AAA488935A7DE6CF7C592D /* MarketGlobalMetricService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7B3EA0C8B9FDEC41837 /* MarketGlobalMetricService.swift */; }; 58AAA48ED47FD19F368385FA /* MetricChartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAAD2AA132E9B13726D8B /* MetricChartViewController.swift */; }; 58AAA49049C7EA04AABC41E9 /* SwapSlippageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA86B59A4D59F08EB334 /* SwapSlippageViewModel.swift */; }; 58AAA4915E1B70248A8DC620 /* SwapApproveViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA43491E0E4F17D020455 /* SwapApproveViewModel.swift */; }; @@ -1926,7 +1768,6 @@ 58AAA4A4D0D7398E7184E7AB /* UITextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFBDA192A490C33DBB95 /* UITextView.swift */; }; 58AAA4AEC3E593C4732D85FF /* MetricChartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA765922F6668954C238E /* MetricChartViewModel.swift */; }; 58AAA4B64068280C684EE5C1 /* MetricChartModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB934A3F1B6490245F1D /* MetricChartModule.swift */; }; - 58AAA4C8FEC03BAFB1B4863E /* MarketGlobalTvlMetricService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAADBB7B760C189AD6032F /* MarketGlobalTvlMetricService.swift */; }; 58AAA4E0703CDD2C6A4D1EED /* DebugPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA4022C5803D2440F43C7 /* DebugPresenter.swift */; }; 58AAA4E1C32E0B48A4CFECCD /* PaymentRequestAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7A94D25C20240FD75C6 /* PaymentRequestAddress.swift */; }; 58AAA4F6DE67EE385EA955C6 /* CoinOverviewViewItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA0B8ECE5854FAB9362AC /* CoinOverviewViewItemFactory.swift */; }; @@ -1941,12 +1782,8 @@ 58AAA57E1D7AF0943273E58A /* UdnAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9A4761030BE9F60C85E /* UdnAddressParserItem.swift */; }; 58AAA59DF74C10DDCA79F35F /* AdditionalDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9E19A578FD13792D2B7 /* AdditionalDataView.swift */; }; 58AAA5A70BBDBD3A9D572261 /* OneInchSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA75A0580C45CC08D89E8 /* OneInchSettingsService.swift */; }; - 58AAA5C000029E9EB74C46C4 /* MarketGlobalMetricViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA02D981360FF0CC50A19 /* MarketGlobalMetricViewController.swift */; }; 58AAA5D1FB4312F714C1D097 /* OneInchSettingsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA78B50AEDADC56B9DEBD /* OneInchSettingsModule.swift */; }; - 58AAA5EF1B46CAFB40139AD2 /* MarketPostModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA42A6EB5242006547A92 /* MarketPostModule.swift */; }; 58AAA604A4728EF375F8937D /* OneInchSettingsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA0D499D632E44F7BE172 /* OneInchSettingsDataSource.swift */; }; - 58AAA60557D3A9E3AE7372E0 /* MarketListDefiDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFE702C2E51EEE209C56 /* MarketListDefiDecorator.swift */; }; - 58AAA626C0B12976749A948E /* MarketTvlSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA4A4F31EAB9164B33299 /* MarketTvlSortHeaderView.swift */; }; 58AAA6371183D7FB9606FEDA /* OneInchSendEvmTransactionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA83DD3B2F70F35F0DFE6 /* OneInchSendEvmTransactionService.swift */; }; 58AAA63F99B1FC1B88B5C8A0 /* UniswapSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA18F732998DCAA76E47C /* UniswapSettings.swift */; }; 58AAA64C3C4E4FA0E4213000 /* SwapApproveModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA251C8ADF1AE43EAF65F /* SwapApproveModule.swift */; }; @@ -1964,9 +1801,7 @@ 58AAA745D76A13D06800BDD1 /* EvmKitManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAC5B00009B199A687EF3 /* EvmKitManager.swift */; }; 58AAA747269D5AE1BBDDA2F7 /* LastBlockInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9D55F97CE089EC67766 /* LastBlockInfo.swift */; }; 58AAA75358DF98C1D7191B81 /* DoubleSpendInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA72BD42697A894C2383C /* DoubleSpendInfoViewController.swift */; }; - 58AAA76E5789D2C9EAC9A2B6 /* MarketSingleSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA51AD262FBDC3D69EEF8 /* MarketSingleSortHeaderViewModel.swift */; }; 58AAA775B9228EEC791ED73D /* MarketGlobalFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA0A9EA8A2210522F38EE /* MarketGlobalFetcher.swift */; }; - 58AAA7B0CC093B05F7487496 /* MarketGlobalMetricModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA775FE9B46DA2910F508 /* MarketGlobalMetricModule.swift */; }; 58AAA7B99324DDA9C53692AD /* SwapApproveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA681BF5F2CBDCD0D8898 /* SwapApproveViewController.swift */; }; 58AAA7C644D47F3B57DF97E0 /* CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB126AA1B83DD40C426F /* CALayer.swift */; }; 58AAA7E6994159CD5FFDB31E /* InputBadgeWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA885C8749392E263A615 /* InputBadgeWrapperView.swift */; }; @@ -1984,18 +1819,15 @@ 58AAA8D086D1DCFADA9A0938 /* OneInchSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7365FA7771481534710 /* OneInchSettingsViewModel.swift */; }; 58AAA8D2A6FD519EFC668EC5 /* CoinPageModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA331E9A43EB0C7F186B1 /* CoinPageModule.swift */; }; 58AAA8D40B3399937CFEB0F2 /* PaymentRequestAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7A94D25C20240FD75C6 /* PaymentRequestAddress.swift */; }; - 58AAA8D67EB6C19719BD760B /* MarketWatchlistService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAABDFE887324FC10AC290 /* MarketWatchlistService.swift */; }; 58AAA8E5EA8901CF69DDE43D /* LockDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA16E4AB334B67FFD891A /* LockDelegate.swift */; }; 58AAA900E2644527A2C78863 /* MetricChartService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8CB22CEF84A71CF044F /* MetricChartService.swift */; }; 58AAA9053CD38F13CD944E2A /* SwapApproveAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA1233617C06AC975285A /* SwapApproveAmountView.swift */; }; 58AAA926E1D95F61CA06EFB8 /* SwapConfirmationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB39CAE1453B9ED024E4 /* SwapConfirmationModule.swift */; }; - 58AAA937A06DD40BD9A64C71 /* MarketGlobalMetricViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA02D981360FF0CC50A19 /* MarketGlobalMetricViewController.swift */; }; 58AAA93B19192D8AE2590A4F /* DebugRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA905C4D766F902C08B65 /* DebugRouter.swift */; }; 58AAA9475B1C057E82B25C76 /* OneInchFeeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAF4E4A24283A9DF0191F /* OneInchFeeService.swift */; }; 58AAA96EA2327421BB3A115B /* SwapDeadlineViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFF25BF263B5EC4188F7 /* SwapDeadlineViewModel.swift */; }; 58AAA9771EA29EC8CDA33C58 /* OneInchSettingsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA78B50AEDADC56B9DEBD /* OneInchSettingsModule.swift */; }; 58AAA98A15442365CFE776F3 /* KeyboardAwareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAACC6B72757C7EDAA8577 /* KeyboardAwareViewController.swift */; }; - 58AAA996622FCD647B51A3C5 /* MarketGlobalMetricModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA775FE9B46DA2910F508 /* MarketGlobalMetricModule.swift */; }; 58AAA996A8547DBE1BF378CE /* SwapApproveService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAADE7CE3F004B908CEDA1 /* SwapApproveService.swift */; }; 58AAA9A289DE179B76AFA99F /* KeyboardAwareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAACC6B72757C7EDAA8577 /* KeyboardAwareViewController.swift */; }; 58AAA9AAB91A30A18A1F724E /* AddressUriParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAD40C9A99F0EDEFCAD14 /* AddressUriParser.swift */; }; @@ -2003,7 +1835,6 @@ 58AAA9AEFE1043B01BEC2D6A /* CoinSelectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9BBAB97C2D21A83956C /* CoinSelectViewController.swift */; }; 58AAA9B29938CA65FA3CB3F0 /* AdditionalDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9E19A578FD13792D2B7 /* AdditionalDataView.swift */; }; 58AAA9E3B53672B3C37B727E /* StepBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA422A0530C0C07E19F2F /* StepBadgeView.swift */; }; - 58AAAA07DC05EF7F912EA184 /* MarketListTvlDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9B26F62DB74FF3830D5 /* MarketListTvlDecorator.swift */; }; 58AAAA19D6C7812306A164EA /* SwapCoinCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFB203A455CB53996F97 /* SwapCoinCardCell.swift */; }; 58AAAA2323F7CFCAB96FCF04 /* CoinPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA353DAC061C2123948FC /* CoinPageViewController.swift */; }; 58AAAA3E05FEB10822DFC8EE /* SwapStepCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA024EB2E850DD3277419 /* SwapStepCell.swift */; }; @@ -2012,23 +1843,15 @@ 58AAAA6AF87DE0EE337BB8AA /* GradientLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAE622FCAB8C2400A3149 /* GradientLayer.swift */; }; 58AAAA71882CB345D56BBA00 /* CoinChartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA55A4A6A97C25F84034F /* CoinChartFactory.swift */; }; 58AAAA7B0493F3790D49AA14 /* SwapAllowanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAACE967F3E51A57A38835 /* SwapAllowanceViewModel.swift */; }; - 58AAAA8975F5B63340672D00 /* MarketWatchlistService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAABDFE887324FC10AC290 /* MarketWatchlistService.swift */; }; 58AAAAC61D3D8AD1AC4BEEAE /* AdditionalDataWithErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8483BC1E85730F04CA3 /* AdditionalDataWithErrorView.swift */; }; - 58AAAAC777502E0C331C109F /* MarketGlobalDefiMetricService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAD81E45666E783B8B2EA /* MarketGlobalDefiMetricService.swift */; }; 58AAAAD2D124AA0323629B0E /* SwapApproveModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA251C8ADF1AE43EAF65F /* SwapApproveModule.swift */; }; 58AAAAE261DEB08128441641 /* AmountDecimalParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAF740AE2BEBD7CEBD563 /* AmountDecimalParser.swift */; }; 58AAAAE64799E5DD40D4C54A /* MetricChartModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB934A3F1B6490245F1D /* MetricChartModule.swift */; }; - 58AAAAEC33A43B54E8E4D3FB /* MarketPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA263DAB58FD63E6A9351 /* MarketPostViewController.swift */; }; - 58AAAAED41A83519EFB94237 /* MarketPostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA11651E3CE29A461BF42 /* MarketPostViewModel.swift */; }; 58AAAAEDC64AE5716BC07673 /* SwapSlippageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAA86B59A4D59F08EB334 /* SwapSlippageViewModel.swift */; }; 58AAAAF8C20AB0E0299A36B8 /* CoinSelectModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAACD2595FD785AEF3C379 /* CoinSelectModule.swift */; }; 58AAAB04DD6CB4DBEE62526C /* ChartModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA5C1F206B755B477A30B /* ChartModule.swift */; }; - 58AAAB25F7EDB3EAE26E690C /* MarketGlobalTvlMetricViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8E1106E31D68FD9181D /* MarketGlobalTvlMetricViewController.swift */; }; 58AAAB32C3D3DCBD004513C7 /* CoinChartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8F53B1A92A391DB1CFF /* CoinChartViewModel.swift */; }; - 58AAAB41ED4FC861D1C99AAC /* MarketOverviewHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA2521E8F8845D96AB865 /* MarketOverviewHeaderCell.swift */; }; - 58AAAB5D89B03B266A4F9B57 /* MarketOverviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFB549AE163AD4F920DD /* MarketOverviewViewController.swift */; }; 58AAAB67059E3F289F557860 /* OneInchSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7365FA7771481534710 /* OneInchSettingsViewModel.swift */; }; - 58AAAB9BE155C6F7630BCE31 /* MarketSingleSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA15F4FA7B9EC091EDFF3 /* MarketSingleSortHeaderView.swift */; }; 58AAAB9E86439B6DE1D22538 /* EvmAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAAC62C5B05463D339BCC /* EvmAddressParserItem.swift */; }; 58AAABA864BFEC1F10F57E4B /* CoinChartService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA13C7C5B258310BA61AF /* CoinChartService.swift */; }; 58AAABC21BB15CAC923A13CB /* CoinCardModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8AD6794AD2AAF462B7B /* CoinCardModule.swift */; }; @@ -2039,10 +1862,8 @@ 58AAAC4F4425F8C33B604020 /* SwapPendingAllowanceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAACF9B71A0C0DCFF7117E /* SwapPendingAllowanceService.swift */; }; 58AAAC635552C279592F60F9 /* EvmAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAAC62C5B05463D339BCC /* EvmAddressParserItem.swift */; }; 58AAAC9A4813120F3B786D18 /* SwapConfirmationAmountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA5BF9EE200DAA24AD42A /* SwapConfirmationAmountCell.swift */; }; - 58AAACA5A8EC9B2A3182395F /* MarketGlobalTvlFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAEA0582FFB81EB6C6263 /* MarketGlobalTvlFetcher.swift */; }; 58AAACCD229B4D4D525A8182 /* CoinPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA6CBFBB0EA959466977D /* CoinPageViewModel.swift */; }; 58AAACD7A57AA93736CDB54D /* SwapApproveAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA1233617C06AC975285A /* SwapApproveAmountView.swift */; }; - 58AAACF322E073F1DDA1FBDC /* MarketTvlSortHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA78BB269FEBB430092A3 /* MarketTvlSortHeaderViewModel.swift */; }; 58AAAD10078FF803A3C27F7C /* MetricChartService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8CB22CEF84A71CF044F /* MetricChartService.swift */; }; 58AAAD15C27B67A91EA11F76 /* AddressUriParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAD40C9A99F0EDEFCAD14 /* AddressUriParser.swift */; }; 58AAAD1BFFE70A777DDF27A9 /* AddressParserChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA7305EF2A12D3DC82B32 /* AddressParserChain.swift */; }; @@ -2070,8 +1891,6 @@ 58AAAE6CFB04C47AC24A69D7 /* MarketGlobalFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA0A9EA8A2210522F38EE /* MarketGlobalFetcher.swift */; }; 58AAAE7CA65D1A4906C5E65E /* SwapSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9828D8742CD3D9995D9 /* SwapSwitchCell.swift */; }; 58AAAE9383600A15C521DBD8 /* InfoModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAD7AC450FEF913E5417F /* InfoModule.swift */; }; - 58AAAEA69AA123E96665E2B7 /* MarketGlobalDefiMetricService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAD81E45666E783B8B2EA /* MarketGlobalDefiMetricService.swift */; }; - 58AAAEB0F729B839B9B99A04 /* MarketListDefiDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFE702C2E51EEE209C56 /* MarketListDefiDecorator.swift */; }; 58AAAEDDF791C28174360A15 /* MetricChartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAC7C8A0B2AECDD436A14 /* MetricChartFactory.swift */; }; 58AAAEEA99ACF936862312B2 /* SwapSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA9828D8742CD3D9995D9 /* SwapSwitchCell.swift */; }; 58AAAF011B2E9CDF8455CA7B /* BaseEvmAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA656A81B2C12F618FB44 /* BaseEvmAdapter.swift */; }; @@ -2079,10 +1898,7 @@ 58AAAF222E553D8DCD123AB2 /* SwapAllowanceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA892221B1283EFC14B9E /* SwapAllowanceService.swift */; }; 58AAAF3B68B9F64DF20FA5AB /* FeeSliderWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAC2D03916C80C8DC5FE5 /* FeeSliderWrapper.swift */; }; 58AAAF4236075971CC88F7ED /* SwapApproveService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAADE7CE3F004B908CEDA1 /* SwapApproveService.swift */; }; - 58AAAF56EF620164D797D60F /* MarketTvlSortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA4A4F31EAB9164B33299 /* MarketTvlSortHeaderView.swift */; }; 58AAAF6248682EE23B3C3D5A /* DebugLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA18F75B95ACBBAE94DF3 /* DebugLogger.swift */; }; - 58AAAF886ADA156E5559EE5B /* MarketOverviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAFB549AE163AD4F920DD /* MarketOverviewViewController.swift */; }; - 58AAAFC5FE754A2286161D16 /* MarketGlobalTvlFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAEA0582FFB81EB6C6263 /* MarketGlobalTvlFetcher.swift */; }; 58AAAFD1F07293D4691F2294 /* MetricChartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAC7C8A0B2AECDD436A14 /* MetricChartFactory.swift */; }; 58AAAFDBA357FC699C07C334 /* AdditionalDataWithErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAA8483BC1E85730F04CA3 /* AdditionalDataWithErrorView.swift */; }; 58AAAFE644C1B236B9714B47 /* CoinSelectViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AAAB692B7C326319D186E4 /* CoinSelectViewModel.swift */; }; @@ -2216,7 +2032,6 @@ ABC9A140E5EF9D0AD4234689 /* SendEip1155ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A9C09ECB9B0CCBAD8C21 /* SendEip1155ViewController.swift */; }; ABC9A14731CC409C5EBC4978 /* DismissPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AA526C8BADA56269C4E0 /* DismissPanGestureRecognizer.swift */; }; ABC9A14877872E0FC7C9D0D2 /* ActionSheetTapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9ACC91C29905F8E7A2046 /* ActionSheetTapView.swift */; }; - ABC9A160495EB67472B97E61 /* MarketWatchlistDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A8B6A5C590B23C6F83C3 /* MarketWatchlistDecorator.swift */; }; ABC9A1636549E626FB32F71A /* WalletTokenBalanceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AB2DC4C4412EFE6BEFF7 /* WalletTokenBalanceCell.swift */; }; ABC9A1798D6E2E4C868DA366 /* Eip1559FeeSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A8E02C3486492E3B12F2 /* Eip1559FeeSettingsViewModel.swift */; }; ABC9A190E478402B48410FCC /* AlertButtonTintColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A87A0C7AA22B19520502 /* AlertButtonTintColor.swift */; }; @@ -2274,7 +2089,6 @@ ABC9A2CA505DB49DE0FB28DD /* WalletTokenBalanceCustomAmountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AD448DC071D8800C6B12 /* WalletTokenBalanceCustomAmountCell.swift */; }; ABC9A2D0ACEDCFA5FDB04D89 /* IndicatorDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A12E4155640075755699 /* IndicatorDataSource.swift */; }; ABC9A2D3D28955B8AD82AFC3 /* BackupTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A5CDF9153AECED3DE50C /* BackupTypeView.swift */; }; - ABC9A2DA629CF38FD7B893EC /* MarketWatchlistDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A8B6A5C590B23C6F83C3 /* MarketWatchlistDecorator.swift */; }; ABC9A2E2F6D884CC8444C029 /* WCSignMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A0643C6E6FA30D7EE473 /* WCSignMessageHandler.swift */; }; ABC9A2E71264B12B7FFC3736 /* WalletConnectListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A3BEB33F6DBE2395FD11 /* WalletConnectListService.swift */; }; ABC9A2E921AE00E0AF5067DE /* CoinProChartModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A021D71EDD24DFB6BA62 /* CoinProChartModule.swift */; }; @@ -2465,7 +2279,6 @@ ABC9A79CFCEBAC442A1B791D /* BackupAppModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A37065F4A8459C416F0A /* BackupAppModule.swift */; }; ABC9A7A9053C6ECF618D0E4A /* WalletConnectSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A4544AB5CA22ADE16417 /* WalletConnectSession.swift */; }; ABC9A7A9E27CC5F93BE5018B /* WalletConnectListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A3BEB33F6DBE2395FD11 /* WalletConnectListService.swift */; }; - ABC9A7AF4EE29CDE045ADEF7 /* MarketCategoryMarketCapFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9ADC1A3B17225B6CC0869 /* MarketCategoryMarketCapFetcher.swift */; }; ABC9A7C2087C3A641C3F9AD4 /* Shake.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A104D916039D690E454E /* Shake.swift */; }; ABC9A7CBFDC0DF741E29EA44 /* Integer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AF26FDCB363793BF66E1 /* Integer.swift */; }; ABC9A7E1F93B0A85976C826D /* UniswapV3Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A253877D9FB972EFB8D7 /* UniswapV3Provider.swift */; }; @@ -2658,7 +2471,6 @@ ABC9AD2688A8DF327A3F92FC /* NoAccountWalletTokenListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A141E4C255C3E450863E /* NoAccountWalletTokenListService.swift */; }; ABC9AD27E074CF3FA292C647 /* IndicatorAdviceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A044BFF4E76CD17835CA /* IndicatorAdviceView.swift */; }; ABC9AD3001AAA0570B503876 /* ManageBarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A6CFDF38D413679D2088 /* ManageBarButtonView.swift */; }; - ABC9AD3276132B33F6045AFF /* MarketCategoryMarketCapFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9ADC1A3B17225B6CC0869 /* MarketCategoryMarketCapFetcher.swift */; }; ABC9AD41E7C88963F6512905 /* ChartIndicatorsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A3758FE2D56036DF27FF /* ChartIndicatorsRepository.swift */; }; ABC9AD46006A85E907826E2B /* EnabledWalletCache_v_0_36.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A68AFE3CF24D2B88808F /* EnabledWalletCache_v_0_36.swift */; }; ABC9AD46AE6B5F432E0D2085 /* WalletTokenBalanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A52822CE6B8830CF5EF4 /* WalletTokenBalanceViewModel.swift */; }; @@ -2974,8 +2786,6 @@ D311DA232BD23C230013DB8F /* MarketAdvancedSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D311DA212BD23C230013DB8F /* MarketAdvancedSearchView.swift */; }; D311DA252BD23C890013DB8F /* ScrollableTabHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D311DA242BD23C890013DB8F /* ScrollableTabHeaderView.swift */; }; D311DA262BD23C890013DB8F /* ScrollableTabHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D311DA242BD23C890013DB8F /* ScrollableTabHeaderView.swift */; }; - D311DA282BD27F5F0013DB8F /* MarketGlobalMetricsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D311DA272BD27F5F0013DB8F /* MarketGlobalMetricsView.swift */; }; - D311DA292BD27F5F0013DB8F /* MarketGlobalMetricsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D311DA272BD27F5F0013DB8F /* MarketGlobalMetricsView.swift */; }; D31369862BEA187E00BA6B5B /* ZcashSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31369852BEA187E00BA6B5B /* ZcashSendHandler.swift */; }; D31369872BEA187E00BA6B5B /* ZcashSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31369852BEA187E00BA6B5B /* ZcashSendHandler.swift */; }; D31369892BEA188D00BA6B5B /* ZcashPreSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31369882BEA188D00BA6B5B /* ZcashPreSendHandler.swift */; }; @@ -3433,11 +3243,8 @@ 11B3502637A858E6DDF9471B /* EvmSyncSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvmSyncSource.swift; sourceTree = ""; }; 11B3502AEB7EF95A590A7B1B /* NftStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftStorage.swift; sourceTree = ""; }; 11B350369A891BEA3A525E5B /* UITabBarItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITabBarItem.swift; sourceTree = ""; }; - 11B3503B9A985B4835FDB03D /* MarketMultiSortHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketMultiSortHeaderView.swift; sourceTree = ""; }; - 11B350465C489A233625E8F2 /* MarketOverviewTopPairsDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopPairsDataSource.swift; sourceTree = ""; }; 11B350575488360C1A598DF3 /* ReceiveSelectCoinViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveSelectCoinViewModel.swift; sourceTree = ""; }; 11B3505A43D9C2787B3BD153 /* PasscodeLockManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeLockManager.swift; sourceTree = ""; }; - 11B3505AD2C1640DEAD8CFFC /* MarketTopViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopViewController.swift; sourceTree = ""; }; 11B35062C72B1D98A2A4EDA9 /* MultiSwapQuotesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiSwapQuotesView.swift; sourceTree = ""; }; 11B3506758F70E9014947BB3 /* CexWithdrawConfirmViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexWithdrawConfirmViewModel.swift; sourceTree = ""; }; 11B3506BFA73130CA9A1FF71 /* CoinOverviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinOverviewView.swift; sourceTree = ""; }; @@ -3459,7 +3266,6 @@ 11B350BD0CE4F979CA88EFF0 /* RestoreModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreModule.swift; sourceTree = ""; }; 11B350BD364F07D1AC759865 /* NSAttributedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = ""; }; 11B350C0CB7083E2738D356C /* ListSectionHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListSectionHeader.swift; sourceTree = ""; }; - 11B350CAB1C54A2CAA4C76F6 /* MarketCategoryModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketCategoryModule.swift; sourceTree = ""; }; 11B350CCAA0C9F2F5279F680 /* TransactionsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionsViewController.swift; sourceTree = ""; }; 11B350CD0F79715E1A5EE8BF /* NftCollectionAssetsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionAssetsService.swift; sourceTree = ""; }; 11B350CDE31673BA1673B620 /* CoinToggleViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinToggleViewModel.swift; sourceTree = ""; }; @@ -3472,7 +3278,6 @@ 11B350F532661482B6170F92 /* IMultiSwapQuote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IMultiSwapQuote.swift; sourceTree = ""; }; 11B350F5D363E9B1D6C9120F /* FormCautionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormCautionCell.swift; sourceTree = ""; }; 11B350F6C5F6ABC288511AF0 /* AccountRecord_v_0_19.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountRecord_v_0_19.swift; sourceTree = ""; }; - 11B350FAB6F1A6E1FCFACB2F /* MarketMultiSortHeaderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketMultiSortHeaderViewModel.swift; sourceTree = ""; }; 11B350FFC1582D23FD709970 /* BlockchainSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockchainSettingsView.swift; sourceTree = ""; }; 11B35100DD6E2DBF905FD19B /* NftCollectionAssetsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionAssetsModule.swift; sourceTree = ""; }; 11B35102BB1E66987670CD1F /* AddBep2TokenBlockchainService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddBep2TokenBlockchainService.swift; sourceTree = ""; }; @@ -3483,7 +3288,6 @@ 11B3513049D27CB1FA264600 /* MnemonicPhraseCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MnemonicPhraseCell.swift; sourceTree = ""; }; 11B35136653741E9703E61DE /* WalletTokenListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletTokenListViewModel.swift; sourceTree = ""; }; 11B3513A7417C236F56E5383 /* CoinValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinValue.swift; sourceTree = ""; }; - 11B3513AC6560B9C37C342F3 /* CoinRankService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinRankService.swift; sourceTree = ""; }; 11B35140CD5BF8B1C26A6278 /* MultiSwapButtonState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiSwapButtonState.swift; sourceTree = ""; }; 11B351436E090F4C05243103 /* NftCollectionOverviewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionOverviewViewModel.swift; sourceTree = ""; }; 11B351454D8FE8FEDA2C1EC9 /* ScanQrBlurView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanQrBlurView.swift; sourceTree = ""; }; @@ -3496,7 +3300,6 @@ 11B351628BA5984C6EBB412E /* CreateAccountSimpleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateAccountSimpleViewController.swift; sourceTree = ""; }; 11B35163E7C4454BBA9E2E9E /* AlertItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertItemCell.swift; sourceTree = ""; }; 11B3516415E7A3217BBB1681 /* AlertRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertRouter.swift; sourceTree = ""; }; - 11B351664970D7EA1F7B50C7 /* CoinRankHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinRankHeaderView.swift; sourceTree = ""; }; 11B3517B0E763E2C217654A7 /* RecoveryPhraseModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseModule.swift; sourceTree = ""; }; 11B3517F84E9913C9030E749 /* CexWithdrawConfirmViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexWithdrawConfirmViewController.swift; sourceTree = ""; }; 11B35185ECC372A193D00A00 /* CoinTreasury.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinTreasury.swift; sourceTree = ""; }; @@ -3544,7 +3347,6 @@ 11B3526A40F07F6C8E77BEF9 /* BlockchainSettingRecord_v_0_24.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockchainSettingRecord_v_0_24.swift; sourceTree = ""; }; 11B3526E11EC0F9CFCC69D17 /* SendAvailableBalanceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendAvailableBalanceViewModel.swift; sourceTree = ""; }; 11B352782BB83C4E447092DB /* BtcBlockchainSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BtcBlockchainSettingsView.swift; sourceTree = ""; }; - 11B3527F1528AA697AAA6E61 /* TopPlatformViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopPlatformViewModel.swift; sourceTree = ""; }; 11B3528090862B6792A76DA4 /* FaqCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaqCell.swift; sourceTree = ""; }; 11B352884D47E0B23DCF2C2C /* AppManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppManager.swift; sourceTree = ""; }; 11B3528DDD55DDA1BAC2BADB /* ActiveAccount_v_0_36.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveAccount_v_0_36.swift; sourceTree = ""; }; @@ -3561,11 +3363,9 @@ 11B352A41EC99ADCC8F3E3E9 /* FormAmountInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormAmountInputView.swift; sourceTree = ""; }; 11B352A8C9C3AA2AB1776F3C /* UnlinkViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnlinkViewController.swift; sourceTree = ""; }; 11B352ABFDEAEEA84D3FDD8B /* AddEvmTokenBlockchainService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddEvmTokenBlockchainService.swift; sourceTree = ""; }; - 11B352AC4F5BE70D055293D7 /* MarketCategoryViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketCategoryViewModel.swift; sourceTree = ""; }; 11B352B4E116BEC01B972A39 /* FaqService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaqService.swift; sourceTree = ""; }; 11B352BACB38FE566F6F575B /* NftEventMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftEventMetadata.swift; sourceTree = ""; }; 11B352BD333C9D69ECB82884 /* BadgeViewNew.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BadgeViewNew.swift; sourceTree = ""; }; - 11B352BDC42A2F717AFAE7BD /* MarketOverviewTopPairsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopPairsService.swift; sourceTree = ""; }; 11B352C2F20DB6266112BE68 /* TransactionsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionsService.swift; sourceTree = ""; }; 11B352C35227943125FF2008 /* HeaderAmountView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderAmountView.swift; sourceTree = ""; }; 11B352CFEDEBF0A01CC7073D /* GuidesModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GuidesModule.swift; sourceTree = ""; }; @@ -3614,7 +3414,6 @@ 11B353A0B705D8EABC5B6827 /* EnabledWallet_v_0_10.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnabledWallet_v_0_10.swift; sourceTree = ""; }; 11B353A64E88BD68714D4D07 /* RestoreViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreViewController.swift; sourceTree = ""; }; 11B353B02ADF5EC5CC83FB33 /* SendHandlerFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendHandlerFactory.swift; sourceTree = ""; }; - 11B353B060BDF272932D3522 /* MarketListMarketFieldDecorator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListMarketFieldDecorator.swift; sourceTree = ""; }; 11B353B4C04282FDBB1B6563 /* Guide.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Guide.swift; sourceTree = ""; }; 11B353BA87FDCB1BCBA92E61 /* InputStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputStackView.swift; sourceTree = ""; }; 11B353C09FE554834C760777 /* SelectorModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorModule.swift; sourceTree = ""; }; @@ -3634,7 +3433,6 @@ 11B3542B6FE4B4F0C0B65369 /* FeeData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeeData.swift; sourceTree = ""; }; 11B3542B81C83F855FB3CD6C /* TonOutgoingTransactionRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TonOutgoingTransactionRecord.swift; sourceTree = ""; }; 11B3543968337A40168D3EB0 /* MarkdownParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownParser.swift; sourceTree = ""; }; - 11B3543F4D196A47EFE3E6F7 /* MarketHeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketHeaderCell.swift; sourceTree = ""; }; 11B3544AC69419F31F20F34E /* TransactionFilterViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionFilterViewModel.swift; sourceTree = ""; }; 11B35450456BE5E3EE8F7391 /* Faq.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Faq.swift; sourceTree = ""; }; 11B354506A9B41DCD49B2807 /* UnlockModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnlockModule.swift; sourceTree = ""; }; @@ -3674,14 +3472,12 @@ 11B355267E1A6678B7B5FCF1 /* AddTokenModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddTokenModule.swift; sourceTree = ""; }; 11B3552D3F84BA594EFE964C /* MarkdownBlockQuoteCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownBlockQuoteCell.swift; sourceTree = ""; }; 11B3553967AFF40F6A9A611A /* CoinPageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinPageView.swift; sourceTree = ""; }; - 11B3554159E6E5B7C1E71F04 /* MarketOverviewService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewService.swift; sourceTree = ""; }; 11B35542A7D7FE1BDC2E73E2 /* AccountType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountType.swift; sourceTree = ""; }; 11B355436F62829DBE3C92B4 /* CellComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellComponent.swift; sourceTree = ""; }; 11B3554BC96C9C24C24CC2B0 /* DuressModeSelectView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DuressModeSelectView.swift; sourceTree = ""; }; 11B35564351D59D37278C723 /* ExtendedKeyService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtendedKeyService.swift; sourceTree = ""; }; 11B35577CFC2384E3A454329 /* EnabledWallet_v_0_20.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnabledWallet_v_0_20.swift; sourceTree = ""; }; 11B3557DF76CFEBE7DA50D81 /* BottomGradientWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomGradientWrapper.swift; sourceTree = ""; }; - 11B3557E5ACDC89EF79C8C0C /* MarketListMarketPairDecorator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListMarketPairDecorator.swift; sourceTree = ""; }; 11B35588D5C27AD3673DEE2F /* AppIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppIcon.swift; sourceTree = ""; }; 11B3558ACECAA1C886FA82C0 /* RecoveryPhraseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseViewController.swift; sourceTree = ""; }; 11B3558D624AF040E9D102DF /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; @@ -3692,9 +3488,7 @@ 11B355ABE89C2793563829BD /* Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; 11B355B546A9CA0324F2F0AE /* AmountInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AmountInputView.swift; sourceTree = ""; }; 11B355B6EFCAB40DC5ACEA3D /* MultiSelectorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiSelectorViewController.swift; sourceTree = ""; }; - 11B355BEB95969D89B3F8876 /* MarketListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListViewModel.swift; sourceTree = ""; }; 11B355C1E3C922BAE804AAF9 /* WalletConnectSessionStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletConnectSessionStorage.swift; sourceTree = ""; }; - 11B355C615D9FE4290671D5D /* MarketTopPairsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopPairsModule.swift; sourceTree = ""; }; 11B355D5EFD2B74DE15F0C2A /* FaqModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaqModule.swift; sourceTree = ""; }; 11B355DF40EB498107EDAA4A /* BrandFooterCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrandFooterCell.swift; sourceTree = ""; }; 11B355E86612AEE00ED19CFE /* BackupManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupManager.swift; sourceTree = ""; }; @@ -3708,7 +3502,6 @@ 11B35614C6E244926AF48701 /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; 11B35615F3ECB5D6E467B49A /* ReceiveSelectCoinService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveSelectCoinService.swift; sourceTree = ""; }; 11B35625BCC4536F39B151F0 /* RestorePrivateKeyViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestorePrivateKeyViewModel.swift; sourceTree = ""; }; - 11B3562819DF141457837340 /* MarketWatchlistToggleService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketWatchlistToggleService.swift; sourceTree = ""; }; 11B3562F83BCEE2720B1C23F /* ITransactionService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ITransactionService.swift; sourceTree = ""; }; 11B356300F9A6A12C29450E7 /* DateFormatterCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateFormatterCache.swift; sourceTree = ""; }; 11B3563ED22080EE222848A5 /* MarkdownImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownImageCell.swift; sourceTree = ""; }; @@ -3721,7 +3514,6 @@ 11B356671FA76C7DEDA50B94 /* SwapApproveConfirmationModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapApproveConfirmationModule.swift; sourceTree = ""; }; 11B3566B18FBFBA85D98D824 /* EnabledWalletCacheManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnabledWalletCacheManager.swift; sourceTree = ""; }; 11B3566DC3A97A5CC3E2C729 /* BalancePrimaryValueManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalancePrimaryValueManager.swift; sourceTree = ""; }; - 11B3566FE007887C3528583C /* MarketWatchlistViewModelOld.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketWatchlistViewModelOld.swift; sourceTree = ""; }; 11B3567314F1A1DF8D1B2910 /* TransactionFilterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionFilterView.swift; sourceTree = ""; }; 11B356861F703A5A5C6630B6 /* LitecoinAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LitecoinAdapter.swift; sourceTree = ""; }; 11B3568F6FAF721301DEC188 /* FormCautionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormCautionView.swift; sourceTree = ""; }; @@ -3746,7 +3538,6 @@ 11B35708A630D70385F34A8B /* NftCollectionModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionModule.swift; sourceTree = ""; }; 11B35711A471C5A45DD87108 /* EvmNetworkViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvmNetworkViewController.swift; sourceTree = ""; }; 11B3572105A456CCDD63E94D /* SecondaryButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondaryButtonStyle.swift; sourceTree = ""; }; - 11B357229D5E717F2051F0AC /* MarketCategoryService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketCategoryService.swift; sourceTree = ""; }; 11B3572B7C2F16CD51F37FF0 /* UIImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImage.swift; sourceTree = ""; }; 11B3572F134D41A670EE9244 /* CexWithdrawNetwork.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexWithdrawNetwork.swift; sourceTree = ""; }; 11B35736BA15E54066036D54 /* BackupMnemonicWordCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupMnemonicWordCell.swift; sourceTree = ""; }; @@ -3766,7 +3557,6 @@ 11B3576C0D8464F74D44EE92 /* BinanceWithdrawHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinanceWithdrawHandler.swift; sourceTree = ""; }; 11B3576F224007FD4154EBE8 /* LockoutManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockoutManager.swift; sourceTree = ""; }; 11B3576FCFC9394BA37975FC /* BackupVerifyWordsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupVerifyWordsViewModel.swift; sourceTree = ""; }; - 11B35770F0C72E1CD3F99985 /* MarketTopService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopService.swift; sourceTree = ""; }; 11B357736B8C29DF38F5DCBA /* AlertViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = ""; }; 11B35779E6353B98B298FF29 /* CurrentDateProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrentDateProvider.swift; sourceTree = ""; }; 11B3577A9294A3EE662872D7 /* TonIncomingTransactionRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TonIncomingTransactionRecord.swift; sourceTree = ""; }; @@ -3791,7 +3581,6 @@ 11B357D222B4819BE881E182 /* WalletTokenListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletTokenListViewController.swift; sourceTree = ""; }; 11B357D7156B86181DD0C6D4 /* TabHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabHeaderView.swift; sourceTree = ""; }; 11B357D89546EBA13B01A1ED /* TransactionsViewItemFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionsViewItemFactory.swift; sourceTree = ""; }; - 11B357E05A8AF5608ECF5D5F /* TopPlatformHeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopPlatformHeaderCell.swift; sourceTree = ""; }; 11B357E9508BF369BDFF7753 /* MarkdownListItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownListItemCell.swift; sourceTree = ""; }; 11B357EC69F650DCA696F48D /* CexAsset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexAsset.swift; sourceTree = ""; }; 11B357EEC98939F9C7AA3271 /* ReceiveDerivationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveDerivationViewModel.swift; sourceTree = ""; }; @@ -3804,13 +3593,11 @@ 11B3580953728946194D1187 /* NftCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionViewController.swift; sourceTree = ""; }; 11B3580D6EDF1BB135965CC5 /* ReceiveSelectorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveSelectorViewController.swift; sourceTree = ""; }; 11B358145A0D9F93ACBC0301 /* CreateAccountModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateAccountModule.swift; sourceTree = ""; }; - 11B3582259AD3A0C55CF6D2C /* MarketOverviewTopPlatformsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopPlatformsService.swift; sourceTree = ""; }; 11B35822E26E7298100CD69D /* LogRecordStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogRecordStorage.swift; sourceTree = ""; }; 11B35828C8D50D0A5B915B2A /* TransactionsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionsModule.swift; sourceTree = ""; }; 11B3583528958D290AD3CE0C /* BackupMnemonicWordsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupMnemonicWordsCell.swift; sourceTree = ""; }; 11B3583932F270503C1DF3F0 /* AdapterFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdapterFactory.swift; sourceTree = ""; }; 11B35847887E070CA535F890 /* UserDefaultsStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsStorage.swift; sourceTree = ""; }; - 11B3584888F2DB8CCFAA90DF /* MarketCategoryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketCategoryViewController.swift; sourceTree = ""; }; 11B3584D2C3754A605975D6C /* SecondaryCircleButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondaryCircleButtonStyle.swift; sourceTree = ""; }; 11B35850DF16D11D45C44A60 /* CexDepositNetworkSelectService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexDepositNetworkSelectService.swift; sourceTree = ""; }; 11B358556C8FC5368E14D81E /* AccountRecordStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountRecordStorage.swift; sourceTree = ""; }; @@ -3828,7 +3615,6 @@ 11B3589893A8995F86F08B1C /* BtcBlockchainSettingsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BtcBlockchainSettingsModule.swift; sourceTree = ""; }; 11B3589B8D488ED1F6912287 /* SelectorButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorButtonStyle.swift; sourceTree = ""; }; 11B358A102692DA01F91413D /* BaseUniswapV2MultiSwapProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseUniswapV2MultiSwapProvider.swift; sourceTree = ""; }; - 11B358A22655004017228F65 /* CoinRankModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinRankModule.swift; sourceTree = ""; }; 11B358A294479046C42D2E6B /* PublicKeysService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicKeysService.swift; sourceTree = ""; }; 11B358A78367D108DD529C1B /* MarkdownHeader3Cell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownHeader3Cell.swift; sourceTree = ""; }; 11B358B22BAF021E8FA028BF /* RecipientAddressCautionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipientAddressCautionCell.swift; sourceTree = ""; }; @@ -3857,19 +3643,16 @@ 11B35935EF1B2237E0289669 /* BaseTransactionsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTransactionsViewModel.swift; sourceTree = ""; }; 11B3593FBD158050C9FEF6B9 /* Misc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Misc.swift; sourceTree = ""; }; 11B3594CBF3EA39A848D22EB /* EditDuressPasscodeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditDuressPasscodeViewModel.swift; sourceTree = ""; }; - 11B359575A4E090B236E84C7 /* CoinRankViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinRankViewModel.swift; sourceTree = ""; }; 11B35957968B4D79EC406D4D /* BottomSheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomSheetViewController.swift; sourceTree = ""; }; 11B3595BAA550B6BEC8C3F72 /* LaunchScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchScreen.swift; sourceTree = ""; }; 11B3595BAB29E195A1317DD1 /* Blockchain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Blockchain.swift; sourceTree = ""; }; 11B35962622F74F89FD32D2B /* EvmAddressViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvmAddressViewModel.swift; sourceTree = ""; }; 11B359636E1AA1BC72CF7B11 /* PoolProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PoolProvider.swift; sourceTree = ""; }; - 11B3596381A93F3A3D2575D6 /* MarketListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListViewController.swift; sourceTree = ""; }; 11B35968D12AAAC828AFE955 /* PrimaryButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimaryButtonStyle.swift; sourceTree = ""; }; 11B35968F5DE9FDA6EC26FCD /* TextInputCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextInputCell.swift; sourceTree = ""; }; 11B359697FC3E92D4111ED5D /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; 11B3596ECFEECF17ADB3BAEF /* RestoreService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreService.swift; sourceTree = ""; }; 11B359706510588C2E7D448B /* BaseCurrencySettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCurrencySettingsViewModel.swift; sourceTree = ""; }; - 11B359715B07FD5316D72A07 /* MarketTopPairsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopPairsViewModel.swift; sourceTree = ""; }; 11B35977188C93500A2CC6B0 /* InputCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputCell.swift; sourceTree = ""; }; 11B3597A2B0B529BE97F85C8 /* WalletHeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletHeaderCell.swift; sourceTree = ""; }; 11B3597E2B288ECD850C1DFE /* PasteInputCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasteInputCell.swift; sourceTree = ""; }; @@ -3909,12 +3692,10 @@ 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 = ""; }; - 11B35A0AF4D03160AF66D1D9 /* MarketOverviewCategoryService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewCategoryService.swift; sourceTree = ""; }; 11B35A0F912218FEC2A196C0 /* CoinInvestorsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinInvestorsViewController.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 = ""; }; - 11B35A1E2AE3DC240D5B785E /* CoinRankViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinRankViewController.swift; sourceTree = ""; }; 11B35A296048CDD27A26FE9E /* EvmAccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvmAccountManager.swift; sourceTree = ""; }; 11B35A296A67CE158347A785 /* SendTonService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendTonService.swift; sourceTree = ""; }; 11B35A2C34C3D62CCA5BFFB5 /* GuidesRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GuidesRepository.swift; sourceTree = ""; }; @@ -3945,7 +3726,6 @@ 11B35AA43C4832521D428799 /* ListSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListSection.swift; sourceTree = ""; }; 11B35AAAC675987369F2DA1B /* BinanceAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinanceAdapter.swift; sourceTree = ""; }; 11B35AAE4114A56DF13ECF0F /* StackViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackViewCell.swift; sourceTree = ""; }; - 11B35AB1D0CE5D8ECE7DDF65 /* MarketOverviewTopPairsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopPairsViewModel.swift; sourceTree = ""; }; 11B35AB755E196D299B81BFB /* CoinMajorHoldersViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinMajorHoldersViewController.swift; sourceTree = ""; }; 11B35ABC3E6C990E3BFA0A7B /* CexWithdrawViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexWithdrawViewController.swift; sourceTree = ""; }; 11B35ABF8159065957CD3EF8 /* SubscriptionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionManager.swift; sourceTree = ""; }; @@ -3953,7 +3733,6 @@ 11B35AD211091A7C8619CEA2 /* CexAssetRecordStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexAssetRecordStorage.swift; sourceTree = ""; }; 11B35AD24681D0A122E6A3C5 /* SendData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendData.swift; sourceTree = ""; }; 11B35ADF518A2F98FF673B4B /* CoinAuditsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinAuditsViewModel.swift; sourceTree = ""; }; - 11B35ADF9BC4D149F86F23E4 /* MarketFilteredListService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketFilteredListService.swift; sourceTree = ""; }; 11B35AE5785634316A1A5DA8 /* WalletBlockchainElementService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletBlockchainElementService.swift; sourceTree = ""; }; 11B35AFE2C95FF73F75652D8 /* ChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartView.swift; sourceTree = ""; }; 11B35B0879F715C0777919AA /* WatchlistWidget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WatchlistWidget.swift; sourceTree = ""; }; @@ -3995,7 +3774,6 @@ 11B35B9F4421EE65B8B09370 /* StatRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatRecord.swift; sourceTree = ""; }; 11B35BAA4EA85B4A3A173498 /* RowButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowButtonStyle.swift; sourceTree = ""; }; 11B35BAABF1F6A9EFF769C47 /* NftCollectionOverviewViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionOverviewViewController.swift; sourceTree = ""; }; - 11B35BB370AE2C896BB9F877 /* TopPlatformViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopPlatformViewController.swift; sourceTree = ""; }; 11B35BB3B8928864A742C83E /* ReceiveAddressModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveAddressModule.swift; sourceTree = ""; }; 11B35BB7206DA0EDBB43C814 /* BalanceCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceCell.swift; sourceTree = ""; }; 11B35BBC5BBCC258824A80F3 /* CexDepositNetworkSelectModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CexDepositNetworkSelectModule.swift; sourceTree = ""; }; @@ -4033,7 +3811,6 @@ 11B35C4D6F474C2EB3687EB4 /* AccountFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountFactory.swift; sourceTree = ""; }; 11B35C4F17D4CC8E89F7DC3B /* NftCollectionOverviewService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionOverviewService.swift; sourceTree = ""; }; 11B35C4FFB99D10A8F343E9C /* LanguageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LanguageManager.swift; sourceTree = ""; }; - 11B35C5CA7497C540FFC5D39 /* MarketTopPairsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopPairsViewController.swift; sourceTree = ""; }; 11B35C6498078B1AFF406256 /* CoinMajorHoldersService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinMajorHoldersService.swift; sourceTree = ""; }; 11B35C6DF4DEE25B8B4B2E28 /* TonAddressParserItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TonAddressParserItem.swift; sourceTree = ""; }; 11B35C6E5282F55B88042F8D /* WalletTokenListViewItemFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletTokenListViewItemFactory.swift; sourceTree = ""; }; @@ -4092,11 +3869,9 @@ 11B35DA9FF23D110A042EDD6 /* NftMetadataSyncer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftMetadataSyncer.swift; sourceTree = ""; }; 11B35DB358405198CF67F11D /* MnemonicInputCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MnemonicInputCell.swift; sourceTree = ""; }; 11B35DB5445B83B51C69D7AE /* TokenTransactionsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenTransactionsService.swift; sourceTree = ""; }; - 11B35DB992C240A4CF24938A /* MarketCategoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketCategoryView.swift; sourceTree = ""; }; 11B35DBDADDA8D4F9D88C7AA /* RecipientAddressInputCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecipientAddressInputCell.swift; sourceTree = ""; }; 11B35DC48EEBE1160676B269 /* ManageAccountService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManageAccountService.swift; sourceTree = ""; }; 11B35DC72F0D8DBBCCE2F988 /* MarkdownVisitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownVisitor.swift; sourceTree = ""; }; - 11B35DCCC2D8CD00EF6A9A77 /* MarketOverviewMetricsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewMetricsCell.swift; sourceTree = ""; }; 11B35DCDDACF2BB1E0748ABB /* RestoreSelectViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreSelectViewModel.swift; sourceTree = ""; }; 11B35DDC338BFE2832C07360 /* TransactionTokenSelectView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionTokenSelectView.swift; sourceTree = ""; }; 11B35DDE879F1628BB2CE523 /* WidgetProd.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = WidgetProd.entitlements; sourceTree = ""; }; @@ -4170,8 +3945,6 @@ 11B35F98E89F83A30870F404 /* ActiveAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveAccount.swift; sourceTree = ""; }; 11B35F99E093B7DDB24D39C9 /* SetPasscodeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetPasscodeViewModel.swift; sourceTree = ""; }; 11B35F9B75F6663FAFCA3177 /* TonAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TonAdapter.swift; sourceTree = ""; }; - 11B35F9BA41AC15436A4B977 /* DropdownSortHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownSortHeaderView.swift; sourceTree = ""; }; - 11B35F9DA79410E7B9C1B0F8 /* MarketTopModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopModule.swift; sourceTree = ""; }; 11B35FA360A91FDE3EB0B85C /* RateAppManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RateAppManager.swift; sourceTree = ""; }; 11B35FA70D9570CB2708E1CA /* BackupVerifyWordsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupVerifyWordsService.swift; sourceTree = ""; }; 11B35FA71AA140CD3764C6BC /* SyncerStateStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncerStateStorage.swift; sourceTree = ""; }; @@ -4186,14 +3959,11 @@ 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 = ""; }; - 1A5640B4F6298D9F326C5EDE /* MarketOverviewTopCoinsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopCoinsViewModel.swift; sourceTree = ""; }; 1A5641572B6E46E18B52A6A9 /* SecuritySettingsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecuritySettingsModule.swift; sourceTree = ""; }; 1A5641679DC88BE355F0F3A0 /* Development.template.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Development.template.xcconfig; sourceTree = ""; }; 1A56417C27A95B429D9F2912 /* MarkdownContentProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownContentProvider.swift; sourceTree = ""; }; - 1A5641A724199908970CFB54 /* MarketNftTopCollectionsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketNftTopCollectionsViewController.swift; sourceTree = ""; }; 1A5641CDB00EF52E18BF70F3 /* AppVersionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppVersionManager.swift; sourceTree = ""; }; 1A5641E505FE004F601943C4 /* PerformanceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTableViewCell.swift; sourceTree = ""; }; - 1A564206FEC56546760B9BEA /* MarketOverviewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewViewModel.swift; sourceTree = ""; }; 1A564215DD6F0D54C1F6C4F7 /* AcademyMarkdownConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AcademyMarkdownConfig.swift; sourceTree = ""; }; 1A56422C196B48931CDE1445 /* SendTransactionError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendTransactionError.swift; sourceTree = ""; }; 1A564293D88587642800717B /* FilterHeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterHeaderCell.swift; sourceTree = ""; }; @@ -4202,7 +3972,6 @@ 1A56432704A2E7A9BE78497B /* ReleaseNotesMarkdownConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReleaseNotesMarkdownConfig.swift; sourceTree = ""; }; 1A56433D5D39CCA995F97777 /* Development.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Development.xcconfig; sourceTree = ""; }; 1A564370A637B30D34776F2A /* Production.template.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = file.template; path = Production.template.xcconfig; sourceTree = ""; }; - 1A5643A672A508BC4CBCABDD /* NftCollectionsMultiSortHeaderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NftCollectionsMultiSortHeaderViewModel.swift; sourceTree = ""; }; 1A5644074A3ACB1DFB63FF92 /* ReleaseNotesService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReleaseNotesService.swift; sourceTree = ""; }; 1A56443BF752CB6537E45F5A /* BlockchainSettingsStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockchainSettingsStorage.swift; sourceTree = ""; }; 1A56444EB2F32DB662981653 /* TitledHighlightedDescriptionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitledHighlightedDescriptionCell.swift; sourceTree = ""; }; @@ -4210,15 +3979,10 @@ 1A56446DB62F52AC4C3C2C30 /* SecuritySettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecuritySettingsViewModel.swift; sourceTree = ""; }; 1A56447C12D91108517ED217 /* UIDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = ""; }; 1A5644A21F9FEC4E2A7B0860 /* PlaceholderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderView.swift; sourceTree = ""; }; - 1A5644E4694DBB0E6E0B10CC /* BaseMarketOverviewTopListDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseMarketOverviewTopListDataSource.swift; sourceTree = ""; }; 1A564504718E7D19F379A9F7 /* AdapterError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdapterError.swift; sourceTree = ""; }; 1A56450DA6DF97C9E1FFE987 /* BitcoinBaseAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitcoinBaseAdapter.swift; sourceTree = ""; }; - 1A564555A67E4DC1DC935A04 /* MarketListWatchViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListWatchViewModel.swift; sourceTree = ""; }; 1A564580B3F739DAC59C623F /* DeepLinkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeepLinkManager.swift; sourceTree = ""; }; 1A56458C7C29504755A09E00 /* LaunchService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchService.swift; sourceTree = ""; }; - 1A56459D85D4859D8A0F4D5A /* MarketTopPlatformsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopPlatformsModule.swift; sourceTree = ""; }; - 1A5645B1C5FD344967B1F4B7 /* MarketOverviewCategoryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewCategoryCell.swift; sourceTree = ""; }; - 1A5646218714BA81DE9B5631 /* MarketOverviewTopCoinsDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopCoinsDataSource.swift; sourceTree = ""; }; 1A5646483957D74946973BEE /* PerformanceContentCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceContentCollectionViewCell.swift; sourceTree = ""; }; 1A56469A2F3EAAEDECFB4034 /* JailbreakService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JailbreakService.swift; sourceTree = ""; }; 1A5646B5D68A302515565030 /* BalanceErrorService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceErrorService.swift; sourceTree = ""; }; @@ -4227,65 +3991,46 @@ 1A5646D49060C3EFF06D0479 /* App.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; 1A564702FB246F315983743E /* BalanceErrorViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceErrorViewModel.swift; sourceTree = ""; }; 1A564730E8F235240D62124B /* HighlightedDescriptionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightedDescriptionView.swift; sourceTree = ""; }; - 1A56477F6FC71270AD53A3AE /* MarketOverviewTopPlatformsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopPlatformsViewModel.swift; sourceTree = ""; }; 1A5647ACB8A65C250F62E07D /* AdapterState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdapterState.swift; sourceTree = ""; }; 1A5647AD7481B36F20D4DDF9 /* MainSettingsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainSettingsModule.swift; sourceTree = ""; }; - 1A5647FA18CC69113ECB6581 /* MarketOverviewGlobalDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewGlobalDataSource.swift; sourceTree = ""; }; 1A564814721244F4D4D87557 /* ReachabilityViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityViewModel.swift; sourceTree = ""; }; 1A56485B094980B68B0A86AE /* ReadMoreTextCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadMoreTextCell.swift; sourceTree = ""; }; 1A564872B7C5F76D8CE55A8B /* BinanceAddressParserItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinanceAddressParserItem.swift; sourceTree = ""; }; 1A564879AD72301AAB78F8F5 /* MainSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainSettingsViewController.swift; sourceTree = ""; }; 1A5648911028181BB1462CFE /* TraitCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TraitCell.swift; sourceTree = ""; }; 1A56489DE231CDDCA75CAEB3 /* AppError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppError.swift; sourceTree = ""; }; - 1A5648E7534C2E7F16C4A2D4 /* MarketTopPlatformsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopPlatformsService.swift; sourceTree = ""; }; 1A5648F3AB070B0ACB98C7EE /* Production.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Production.xcconfig; sourceTree = ""; }; 1A564920282E84A6E7EE05EB /* SendEthereumErrorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendEthereumErrorCell.swift; sourceTree = ""; }; - 1A564995DE20E52E8E0F1E6A /* MarketTopPlatformsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopPlatformsViewModel.swift; sourceTree = ""; }; - 1A5649C0BD100768C726B4FB /* TopPlatformService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopPlatformService.swift; sourceTree = ""; }; - 1A5649C48B3AABC56D2512ED /* MarketOverviewGlobalViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewGlobalViewModel.swift; sourceTree = ""; }; 1A5649C6FFC694CD18A8B39A /* AddressUri.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressUri.swift; sourceTree = ""; }; - 1A5649E41FE690AF0A712426 /* MarketNftTopCollectionsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketNftTopCollectionsViewModel.swift; sourceTree = ""; }; 1A564A144576DB93334E1682 /* ScanQrViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanQrViewController.swift; sourceTree = ""; }; 1A564A1B86DF22E86F0BB442 /* TopPlatformMarketCapFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopPlatformMarketCapFetcher.swift; sourceTree = ""; }; 1A564A55E5866D6081EA6F69 /* EnabledWallet_v_0_13.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnabledWallet_v_0_13.swift; sourceTree = ""; }; 1A564A6A5C4F3080690AE93F /* ConvertedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertedError.swift; sourceTree = ""; }; - 1A564A6D161EAD22626332C1 /* MarketOverviewCategoryDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewCategoryDataSource.swift; sourceTree = ""; }; 1A564AB0B646F7A92DD188F2 /* BalanceErrorModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceErrorModule.swift; sourceTree = ""; }; - 1A564ADD13E597F423249CA3 /* MarketOverviewCategoryViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewCategoryViewModel.swift; sourceTree = ""; }; 1A564AFF2709E27114985A8D /* AppVersionStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppVersionStorage.swift; sourceTree = ""; }; 1A564B1C051AF2C87C670563 /* FilterHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterHeaderView.swift; sourceTree = ""; }; - 1A564B44985D1169593F202C /* MarketOverviewTopPlatformsDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopPlatformsDataSource.swift; sourceTree = ""; }; 1A564B73ABBEFC58A13D501E /* PerformanceSideCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceSideCollectionViewCell.swift; sourceTree = ""; }; 1A564B7C35C5B235D2BBAC2C /* AppVersion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = ""; }; 1A564BB88BF3ED779F8C21DC /* BlurManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurManager.swift; sourceTree = ""; }; 1A564BCC9DD29DB5455669A5 /* HighlightedDescriptionBaseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightedDescriptionBaseView.swift; sourceTree = ""; }; - 1A564BDA5600859626D99BB4 /* TopPlatformModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopPlatformModule.swift; sourceTree = ""; }; 1A564BE241BFC5DD59D0FB7C /* BtcRestoreMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BtcRestoreMode.swift; sourceTree = ""; }; 1A564BF724C69C237E309C07 /* BitcoinCashAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitcoinCashAdapter.swift; sourceTree = ""; }; 1A564C46FB773A67E29D9D32 /* BlockchainSettingRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockchainSettingRecord.swift; sourceTree = ""; }; 1A564C4B0D13BC7214419A3E /* GradientClippingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientClippingView.swift; sourceTree = ""; }; - 1A564C4DB4A57CCF2C5EFB78 /* MarketTopPlatformsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTopPlatformsViewController.swift; sourceTree = ""; }; - 1A564C5CC7EC339C3113869D /* MarketListTopPlatformDecorator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListTopPlatformDecorator.swift; sourceTree = ""; }; 1A564CB28708314AE0A69424 /* TitledHighlightedDescriptionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitledHighlightedDescriptionView.swift; sourceTree = ""; }; - 1A564CC5878BF33B8CE1F339 /* MarketListNftCollectionDecorator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListNftCollectionDecorator.swift; sourceTree = ""; }; 1A564CE10FD5FEC14EF38BD8 /* PrivacyPolicyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyViewController.swift; sourceTree = ""; }; 1A564CE56CEC73B78C9DB6B5 /* BalanceErrorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceErrorViewController.swift; sourceTree = ""; }; 1A564CF35E7A07E96B704ADA /* PlaceholderViewModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderViewModule.swift; sourceTree = ""; }; - 1A564D12426BCA027C67377E /* MarketNftTopCollectionsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketNftTopCollectionsService.swift; sourceTree = ""; }; 1A564D2011D7A4E80B2B7B92 /* JailbreakTestManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JailbreakTestManager.swift; sourceTree = ""; }; 1A564D5E55767404ED6C88E0 /* Decimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decimal.swift; sourceTree = ""; }; - 1A564D661F3AE561D7FE9FAA /* MarketOverviewTopCoinsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewTopCoinsService.swift; sourceTree = ""; }; 1A564D73251DBFA0CFE34D12 /* MainSettingsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainSettingsService.swift; sourceTree = ""; }; 1A564D7B1F36B1C4AB4CBF3A /* BasePerformanceCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasePerformanceCollectionViewCell.swift; sourceTree = ""; }; 1A564D8AD6D160F27C021F48 /* ReachabilityService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityService.swift; sourceTree = ""; }; - 1A564D8F8A8A63BC9BEAAD56 /* TopPlatformsMultiSortHeaderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopPlatformsMultiSortHeaderViewModel.swift; sourceTree = ""; }; 1A564DEB9782FF55EFFD8CCA /* DeepLinkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeepLinkService.swift; sourceTree = ""; }; - 1A564E5282C3C22DA85141AF /* MarketNftTopCollectionsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketNftTopCollectionsModule.swift; sourceTree = ""; }; 1A564E6A6B7E18C287A1D77D /* TransactionDataSortMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionDataSortMode.swift; sourceTree = ""; }; 1A564E86CCEAD0F9956664D4 /* ThemeActionSheetController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeActionSheetController.swift; sourceTree = ""; }; 1A564EA6F1CCDF88F78351F8 /* ThemeSearchViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeSearchViewController.swift; sourceTree = ""; }; 1A564EA8CD67010BFFC57AAB /* DashAddressParserItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashAddressParserItem.swift; sourceTree = ""; }; - 1A564EDF0FD6A1D1575D1EFB /* MarketOverviewGlobalService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewGlobalService.swift; sourceTree = ""; }; 1A564FF31C5E879781A2D5E0 /* TraitsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TraitsCell.swift; sourceTree = ""; }; 2FA5D02D8F5C2AE32C6FF923 /* KitCleaner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KitCleaner.swift; sourceTree = ""; }; 2FA5D0F4DBA8FC1F917AA95B /* SendSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendSettingsViewController.swift; sourceTree = ""; }; @@ -4356,7 +4101,6 @@ 2FA5DF48D44BB409FB94CED9 /* UnknownSwapTransactionRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnknownSwapTransactionRecord.swift; sourceTree = ""; }; 2FA5DF5B8B69876A526CCDDD /* BinanceChainOutgoingTransactionRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinanceChainOutgoingTransactionRecord.swift; sourceTree = ""; }; 2FA5DFE7C4A198C235B2EAB5 /* TransactionAdapterManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionAdapterManager.swift; sourceTree = ""; }; - 3AB682BC25BADD97002197A5 /* MarketOverviewModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewModule.swift; sourceTree = ""; }; 3AF9F617253EF555000626A8 /* ZcashTransactionPool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashTransactionPool.swift; sourceTree = ""; }; 3AF9F618253EF555000626A8 /* ZcashAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashAdapter.swift; sourceTree = ""; }; 3AF9F619253EF555000626A8 /* ZcashTransactionWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashTransactionWrapper.swift; sourceTree = ""; }; @@ -4376,14 +4120,11 @@ 50EED191218822FA00E200AD /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; 50EED192218822FA00E200AD /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; 58AAA024EB2E850DD3277419 /* SwapStepCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapStepCell.swift; sourceTree = ""; }; - 58AAA02D981360FF0CC50A19 /* MarketGlobalMetricViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalMetricViewController.swift; sourceTree = ""; }; 58AAA0A9EA8A2210522F38EE /* MarketGlobalFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalFetcher.swift; sourceTree = ""; }; 58AAA0B8ECE5854FAB9362AC /* CoinOverviewViewItemFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinOverviewViewItemFactory.swift; sourceTree = ""; }; 58AAA0D499D632E44F7BE172 /* OneInchSettingsDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OneInchSettingsDataSource.swift; sourceTree = ""; }; - 58AAA11651E3CE29A461BF42 /* MarketPostViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketPostViewModel.swift; sourceTree = ""; }; 58AAA1233617C06AC975285A /* SwapApproveAmountView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapApproveAmountView.swift; sourceTree = ""; }; 58AAA13C7C5B258310BA61AF /* CoinChartService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinChartService.swift; sourceTree = ""; }; - 58AAA15F4FA7B9EC091EDFF3 /* MarketSingleSortHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketSingleSortHeaderView.swift; sourceTree = ""; }; 58AAA16C7E337511638808E5 /* DebugInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugInteractor.swift; sourceTree = ""; }; 58AAA16E4AB334B67FFD891A /* LockDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockDelegate.swift; sourceTree = ""; }; 58AAA18F732998DCAA76E47C /* UniswapSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniswapSettings.swift; sourceTree = ""; }; @@ -4392,9 +4133,7 @@ 58AAA246206AF337B91809BE /* BitcoinAddressParserItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitcoinAddressParserItem.swift; sourceTree = ""; }; 58AAA24B6EB7103CB072A53D /* FeeSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeeSlider.swift; sourceTree = ""; }; 58AAA251C8ADF1AE43EAF65F /* SwapApproveModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapApproveModule.swift; sourceTree = ""; }; - 58AAA2521E8F8845D96AB865 /* MarketOverviewHeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewHeaderCell.swift; sourceTree = ""; }; 58AAA25A23A8EBB537DD56C2 /* AddressResolutionProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressResolutionProvider.swift; sourceTree = ""; }; - 58AAA263DAB58FD63E6A9351 /* MarketPostViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketPostViewController.swift; sourceTree = ""; }; 58AAA27BACBAFC7A19DC36B6 /* UniswapSettingsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniswapSettingsModule.swift; sourceTree = ""; }; 58AAA2B7F82F42442ED27A67 /* DownloadService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadService.swift; sourceTree = ""; }; 58AAA312DD0792117182B64E /* Eip20Adapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Eip20Adapter.swift; sourceTree = ""; }; @@ -4404,18 +4143,13 @@ 58AAA3C555FBFB5423CCF8E0 /* FeeSliderValueView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeeSliderValueView.swift; sourceTree = ""; }; 58AAA4022C5803D2440F43C7 /* DebugPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugPresenter.swift; sourceTree = ""; }; 58AAA422A0530C0C07E19F2F /* StepBadgeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepBadgeView.swift; sourceTree = ""; }; - 58AAA42A6EB5242006547A92 /* MarketPostModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketPostModule.swift; sourceTree = ""; }; 58AAA43491E0E4F17D020455 /* SwapApproveViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapApproveViewModel.swift; sourceTree = ""; }; 58AAA444C885BCC354F1B7B3 /* CoinPageMarkdownParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinPageMarkdownParser.swift; sourceTree = ""; }; - 58AAA4A4F31EAB9164B33299 /* MarketTvlSortHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTvlSortHeaderView.swift; sourceTree = ""; }; - 58AAA50A504CFA74CA19A415 /* MarketMetricView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketMetricView.swift; sourceTree = ""; }; - 58AAA51AD262FBDC3D69EEF8 /* MarketSingleSortHeaderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketSingleSortHeaderViewModel.swift; sourceTree = ""; }; 58AAA54E84B5C1B68644AE46 /* SimpleSheetTitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleSheetTitleView.swift; sourceTree = ""; }; 58AAA55A4A6A97C25F84034F /* CoinChartFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinChartFactory.swift; sourceTree = ""; }; 58AAA5BF9EE200DAA24AD42A /* SwapConfirmationAmountCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapConfirmationAmountCell.swift; sourceTree = ""; }; 58AAA5C1F206B755B477A30B /* ChartModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartModule.swift; sourceTree = ""; }; 58AAA656A81B2C12F618FB44 /* BaseEvmAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseEvmAdapter.swift; sourceTree = ""; }; - 58AAA657E30EBD52A5E06ACF /* MarketPostService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketPostService.swift; sourceTree = ""; }; 58AAA681BF5F2CBDCD0D8898 /* SwapApproveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapApproveViewController.swift; sourceTree = ""; }; 58AAA6CBFBB0EA959466977D /* CoinPageViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinPageViewModel.swift; sourceTree = ""; }; 58AAA6FB0AF97333CD9D007F /* InfoSeparatorHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoSeparatorHeaderView.swift; sourceTree = ""; }; @@ -4426,13 +4160,9 @@ 58AAA75A0580C45CC08D89E8 /* OneInchSettingsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OneInchSettingsService.swift; sourceTree = ""; }; 58AAA765922F6668954C238E /* MetricChartViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetricChartViewModel.swift; sourceTree = ""; }; 58AAA76748B32A4D8FCD765A /* UniswapSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniswapSettingsViewModel.swift; sourceTree = ""; }; - 58AAA775FE9B46DA2910F508 /* MarketGlobalMetricModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalMetricModule.swift; sourceTree = ""; }; 58AAA78B50AEDADC56B9DEBD /* OneInchSettingsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OneInchSettingsModule.swift; sourceTree = ""; }; - 58AAA78BB269FEBB430092A3 /* MarketTvlSortHeaderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketTvlSortHeaderViewModel.swift; sourceTree = ""; }; 58AAA7A94D25C20240FD75C6 /* PaymentRequestAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentRequestAddress.swift; sourceTree = ""; }; - 58AAA7B3EA0C8B9FDEC41837 /* MarketGlobalMetricService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalMetricService.swift; sourceTree = ""; }; 58AAA7C8532511E4BCD9C8D9 /* SwapAllowanceCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapAllowanceCell.swift; sourceTree = ""; }; - 58AAA7D27615D192FBC5486E /* MarketWatchlistModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketWatchlistModule.swift; sourceTree = ""; }; 58AAA7D7F06F7C044DF9CE0A /* MarketGlobalModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalModule.swift; sourceTree = ""; }; 58AAA80C6D2024281A5FA3E5 /* SwapCoinCardViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapCoinCardViewModel.swift; sourceTree = ""; }; 58AAA83833C970A2DC467715 /* InfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoViewController.swift; sourceTree = ""; }; @@ -4443,23 +4173,17 @@ 58AAA8AD6794AD2AAF462B7B /* CoinCardModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinCardModule.swift; sourceTree = ""; }; 58AAA8B7E47FF3B010851E58 /* Global.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Global.swift; sourceTree = ""; }; 58AAA8CB22CEF84A71CF044F /* MetricChartService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetricChartService.swift; sourceTree = ""; }; - 58AAA8E1106E31D68FD9181D /* MarketGlobalTvlMetricViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalTvlMetricViewController.swift; sourceTree = ""; }; 58AAA8F53B1A92A391DB1CFF /* CoinChartViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinChartViewModel.swift; sourceTree = ""; }; - 58AAA8FDCCC09B609C7D0FEA /* MarketViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketViewController.swift; sourceTree = ""; }; 58AAA905C4D766F902C08B65 /* DebugRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugRouter.swift; sourceTree = ""; }; 58AAA9828D8742CD3D9995D9 /* SwapSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapSwitchCell.swift; sourceTree = ""; }; 58AAA9A4761030BE9F60C85E /* UdnAddressParserItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UdnAddressParserItem.swift; sourceTree = ""; }; - 58AAA9B26F62DB74FF3830D5 /* MarketListTvlDecorator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListTvlDecorator.swift; sourceTree = ""; }; 58AAA9BBAB97C2D21A83956C /* CoinSelectViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinSelectViewController.swift; sourceTree = ""; }; 58AAA9D55F97CE089EC67766 /* LastBlockInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LastBlockInfo.swift; sourceTree = ""; }; 58AAA9D5D29115C5F435CF1B /* ChartConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartConfiguration.swift; sourceTree = ""; }; 58AAA9E19A578FD13792D2B7 /* AdditionalDataView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdditionalDataView.swift; sourceTree = ""; }; 58AAA9F2F3A6F483B0D67E18 /* DataStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataStatus.swift; sourceTree = ""; }; - 58AAAA1B62A6A1A278BE06AA /* MarketWatchlistViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketWatchlistViewController.swift; sourceTree = ""; }; - 58AAAA3930D3CB65CC545658 /* GradientPercentCircle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientPercentCircle.swift; sourceTree = ""; }; 58AAAA6EA2DAD95D2CB417FD /* DebugViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugViewController.swift; sourceTree = ""; }; 58AAAA86B59A4D59F08EB334 /* SwapSlippageViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapSlippageViewModel.swift; sourceTree = ""; }; - 58AAAA9DFF1F23B0B8A8CEAD /* MarketViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketViewModel.swift; sourceTree = ""; }; 58AAAAA7456EB952A3E5A53F /* AddressService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressService.swift; sourceTree = ""; }; 58AAAAC62C5B05463D339BCC /* EvmAddressParserItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvmAddressParserItem.swift; sourceTree = ""; }; 58AAAAD2AA132E9B13726D8B /* MetricChartViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetricChartViewController.swift; sourceTree = ""; }; @@ -4467,7 +4191,6 @@ 58AAAB39CAE1453B9ED024E4 /* SwapConfirmationModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapConfirmationModule.swift; sourceTree = ""; }; 58AAAB692B7C326319D186E4 /* CoinSelectViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinSelectViewModel.swift; sourceTree = ""; }; 58AAAB934A3F1B6490245F1D /* MetricChartModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetricChartModule.swift; sourceTree = ""; }; - 58AAABDFE887324FC10AC290 /* MarketWatchlistService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketWatchlistService.swift; sourceTree = ""; }; 58AAAC2D03916C80C8DC5FE5 /* FeeSliderWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeeSliderWrapper.swift; sourceTree = ""; }; 58AAAC5B00009B199A687EF3 /* EvmKitManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvmKitManager.swift; sourceTree = ""; }; 58AAAC5B35D17E82D59F7183 /* SwapConfirmationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapConfirmationViewController.swift; sourceTree = ""; }; @@ -4479,20 +4202,15 @@ 58AAAD02C2210D9DA14D1E21 /* UniswapSettingsDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniswapSettingsDataSource.swift; sourceTree = ""; }; 58AAAD40C9A99F0EDEFCAD14 /* AddressUriParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressUriParser.swift; sourceTree = ""; }; 58AAAD7AC450FEF913E5417F /* InfoModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoModule.swift; sourceTree = ""; }; - 58AAAD81E45666E783B8B2EA /* MarketGlobalDefiMetricService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalDefiMetricService.swift; sourceTree = ""; }; - 58AAADBB7B760C189AD6032F /* MarketGlobalTvlMetricService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalTvlMetricService.swift; sourceTree = ""; }; 58AAADD445F174344AFB6AAC /* DebugModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugModule.swift; sourceTree = ""; }; 58AAADE7CE3F004B908CEDA1 /* SwapApproveService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapApproveService.swift; sourceTree = ""; }; 58AAAE153E9683CB79DCF857 /* SelectorButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorButton.swift; sourceTree = ""; }; 58AAAE622FCAB8C2400A3149 /* GradientLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientLayer.swift; sourceTree = ""; }; - 58AAAEA0582FFB81EB6C6263 /* MarketGlobalTvlFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketGlobalTvlFetcher.swift; sourceTree = ""; }; 58AAAEB2257174A64DE5E51B /* SwapViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapViewModel.swift; sourceTree = ""; }; 58AAAF4E4A24283A9DF0191F /* OneInchFeeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OneInchFeeService.swift; sourceTree = ""; }; 58AAAF740AE2BEBD7CEBD563 /* AmountDecimalParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AmountDecimalParser.swift; sourceTree = ""; }; 58AAAFB203A455CB53996F97 /* SwapCoinCardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapCoinCardCell.swift; sourceTree = ""; }; - 58AAAFB549AE163AD4F920DD /* MarketOverviewViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketOverviewViewController.swift; sourceTree = ""; }; 58AAAFBDA192A490C33DBB95 /* UITextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITextView.swift; sourceTree = ""; }; - 58AAAFE702C2E51EEE209C56 /* MarketListDefiDecorator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketListDefiDecorator.swift; sourceTree = ""; }; 58AAAFF25BF263B5EC4188F7 /* SwapDeadlineViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapDeadlineViewModel.swift; sourceTree = ""; }; 58AAAFF6E494F623AD62AF95 /* UniswapSettingsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniswapSettingsService.swift; sourceTree = ""; }; 6B146A932A52A69400648C10 /* ChartIndicatorSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartIndicatorSettingsViewController.swift; sourceTree = ""; }; @@ -4683,7 +4401,6 @@ ABC9A89B361346FFDB04E48A /* UniswapV3Service.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniswapV3Service.swift; sourceTree = ""; }; ABC9A8A353E491AAD3EDA120 /* ContactBookContactViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactBookContactViewController.swift; sourceTree = ""; }; ABC9A8B3C65C9F0285483160 /* SendZcashViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendZcashViewController.swift; sourceTree = ""; }; - ABC9A8B6A5C590B23C6F83C3 /* MarketWatchlistDecorator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketWatchlistDecorator.swift; sourceTree = ""; }; ABC9A8C0A9FBFB57996E8A8C /* UnspentOutputsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnspentOutputsCell.swift; sourceTree = ""; }; ABC9A8C6A291BACCADF0E443 /* UnspentOutputsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnspentOutputsViewModel.swift; sourceTree = ""; }; ABC9A8CE84FA36438BE4D6B5 /* FileManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = ""; }; @@ -4786,7 +4503,6 @@ ABC9ADA345301F29B947F281 /* RestoreFileConfigurationModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreFileConfigurationModule.swift; sourceTree = ""; }; ABC9ADB77831DCB474B24C8A /* SendFeeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendFeeService.swift; sourceTree = ""; }; ABC9ADC0B58A4ECA7EB76CCB /* BaseAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseAnimation.swift; sourceTree = ""; }; - ABC9ADC1A3B17225B6CC0869 /* MarketCategoryMarketCapFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketCategoryMarketCapFetcher.swift; sourceTree = ""; }; ABC9ADCE6C6975672E185951 /* MultiSwapSlippageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiSwapSlippageView.swift; sourceTree = ""; }; ABC9ADE822BC024F9B798211 /* BottomGradientHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomGradientHolder.swift; sourceTree = ""; }; ABC9ADF114FCFABEA148AF04 /* SendTimeLockErrorService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendTimeLockErrorService.swift; sourceTree = ""; }; @@ -4934,7 +4650,6 @@ D311DA1E2BD115240013DB8F /* MarketGlobalViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketGlobalViewModel.swift; sourceTree = ""; }; D311DA212BD23C230013DB8F /* MarketAdvancedSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketAdvancedSearchView.swift; sourceTree = ""; }; D311DA242BD23C890013DB8F /* ScrollableTabHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollableTabHeaderView.swift; sourceTree = ""; }; - D311DA272BD27F5F0013DB8F /* MarketGlobalMetricsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketGlobalMetricsView.swift; sourceTree = ""; }; D31369852BEA187E00BA6B5B /* ZcashSendHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZcashSendHandler.swift; sourceTree = ""; }; D31369882BEA188D00BA6B5B /* ZcashPreSendHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZcashPreSendHandler.swift; sourceTree = ""; }; D31C4759238BF175008CB818 /* MnemonicDerivation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MnemonicDerivation.swift; sourceTree = ""; }; @@ -5220,17 +4935,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 11B35022BB7BE673C5108390 /* MarketTopPairs */ = { - isa = PBXGroup; - children = ( - 11B3557E5ACDC89EF79C8C0C /* MarketListMarketPairDecorator.swift */, - 11B35C5CA7497C540FFC5D39 /* MarketTopPairsViewController.swift */, - 11B359715B07FD5316D72A07 /* MarketTopPairsViewModel.swift */, - 11B355C615D9FE4290671D5D /* MarketTopPairsModule.swift */, - ); - path = MarketTopPairs; - sourceTree = ""; - }; 11B35043F81AA7646DFDDBBC /* CoinInvestors */ = { isa = PBXGroup; children = ( @@ -5242,18 +4946,6 @@ path = CoinInvestors; sourceTree = ""; }; - 11B3508440D2593C95D34386 /* MarketCategory */ = { - isa = PBXGroup; - children = ( - 11B350CAB1C54A2CAA4C76F6 /* MarketCategoryModule.swift */, - 11B357229D5E717F2051F0AC /* MarketCategoryService.swift */, - 11B352AC4F5BE70D055293D7 /* MarketCategoryViewModel.swift */, - ABC9ADC1A3B17225B6CC0869 /* MarketCategoryMarketCapFetcher.swift */, - 11B3584888F2DB8CCFAA90DF /* MarketCategoryViewController.swift */, - ); - path = MarketCategory; - sourceTree = ""; - }; 11B350A2E7EE706CB00F6E34 /* BackupVerifyWords */ = { isa = PBXGroup; children = ( @@ -5525,16 +5217,6 @@ path = Pool; sourceTree = ""; }; - 11B352D7FBB7101D346C9CCF /* TopPairs */ = { - isa = PBXGroup; - children = ( - 11B350465C489A233625E8F2 /* MarketOverviewTopPairsDataSource.swift */, - 11B35AB1D0CE5D8ECE7DDF65 /* MarketOverviewTopPairsViewModel.swift */, - 11B352BDC42A2F717AFAE7BD /* MarketOverviewTopPairsService.swift */, - ); - path = TopPairs; - sourceTree = ""; - }; 11B352FE5BF3F643F4A9CD99 /* Cells */ = { isa = PBXGroup; children = ( @@ -5638,16 +5320,6 @@ path = UserInterface; sourceTree = ""; }; - 11B353B7A5F3850C328543E8 /* MarketTop */ = { - isa = PBXGroup; - children = ( - 11B35F9DA79410E7B9C1B0F8 /* MarketTopModule.swift */, - 11B35770F0C72E1CD3F99985 /* MarketTopService.swift */, - 11B3505AD2C1640DEAD8CFFC /* MarketTopViewController.swift */, - ); - path = MarketTop; - sourceTree = ""; - }; 11B353F19C7361EF351410B1 /* NftCollection */ = { isa = PBXGroup; children = ( @@ -5685,14 +5357,6 @@ path = Alert; sourceTree = ""; }; - 11B3546A0ED6C1FCC3C5A097 /* FilteredList */ = { - isa = PBXGroup; - children = ( - 11B35ADF9BC4D149F86F23E4 /* MarketFilteredListService.swift */, - ); - path = FilteredList; - sourceTree = ""; - }; 11B3546A6E6F3CC013C9FF44 /* SwiftUI */ = { isa = PBXGroup; children = ( @@ -5960,18 +5624,6 @@ path = Modules; sourceTree = ""; }; - 11B354B9064677BDA5946B48 /* Ranks */ = { - isa = PBXGroup; - children = ( - 11B3513AC6560B9C37C342F3 /* CoinRankService.swift */, - 11B359575A4E090B236E84C7 /* CoinRankViewModel.swift */, - 11B35A1E2AE3DC240D5B785E /* CoinRankViewController.swift */, - 11B358A22655004017228F65 /* CoinRankModule.swift */, - 11B351664970D7EA1F7B50C7 /* CoinRankHeaderView.swift */, - ); - path = Ranks; - sourceTree = ""; - }; 11B354D11B72A988BA1D8F59 /* CoinMarkets */ = { isa = PBXGroup; children = ( @@ -6648,18 +6300,6 @@ path = RestoreSettings; sourceTree = ""; }; - 11B35AAFE626B8D1806D8960 /* MarketList */ = { - isa = PBXGroup; - children = ( - 11B3562819DF141457837340 /* MarketWatchlistToggleService.swift */, - 11B3596381A93F3A3D2575D6 /* MarketListViewController.swift */, - 11B355BEB95969D89B3F8876 /* MarketListViewModel.swift */, - 11B353B060BDF272932D3522 /* MarketListMarketFieldDecorator.swift */, - 1A564555A67E4DC1DC935A04 /* MarketListWatchViewModel.swift */, - ); - path = MarketList; - sourceTree = ""; - }; 11B35AC73BD1A5E8D91C19E9 /* CoinToggle */ = { isa = PBXGroup; children = ( @@ -7198,17 +6838,6 @@ path = BalanceError; sourceTree = ""; }; - 1A56441B781D474BC4F6FA85 /* Category */ = { - isa = PBXGroup; - children = ( - 11B35A0AF4D03160AF66D1D9 /* MarketOverviewCategoryService.swift */, - 1A564ADD13E597F423249CA3 /* MarketOverviewCategoryViewModel.swift */, - 1A564A6D161EAD22626332C1 /* MarketOverviewCategoryDataSource.swift */, - 1A5645B1C5FD344967B1F4B7 /* MarketOverviewCategoryCell.swift */, - ); - path = Category; - sourceTree = ""; - }; 1A564533BEABADF4DC5F8A25 /* Main */ = { isa = PBXGroup; children = ( @@ -7221,29 +6850,6 @@ path = Main; sourceTree = ""; }; - 1A56459494751BD5A4416ECB /* MarketTopPlatforms */ = { - isa = PBXGroup; - children = ( - 1A56459D85D4859D8A0F4D5A /* MarketTopPlatformsModule.swift */, - 1A5648E7534C2E7F16C4A2D4 /* MarketTopPlatformsService.swift */, - 1A564995DE20E52E8E0F1E6A /* MarketTopPlatformsViewModel.swift */, - 1A564C4DB4A57CCF2C5EFB78 /* MarketTopPlatformsViewController.swift */, - 1A564D8F8A8A63BC9BEAAD56 /* TopPlatformsMultiSortHeaderViewModel.swift */, - 1A564C5CC7EC339C3113869D /* MarketListTopPlatformDecorator.swift */, - ); - path = MarketTopPlatforms; - sourceTree = ""; - }; - 1A5645A040DB85EC7ED82369 /* TopCoins */ = { - isa = PBXGroup; - children = ( - 1A564D661F3AE561D7FE9FAA /* MarketOverviewTopCoinsService.swift */, - 1A5640B4F6298D9F326C5EDE /* MarketOverviewTopCoinsViewModel.swift */, - 1A5646218714BA81DE9B5631 /* MarketOverviewTopCoinsDataSource.swift */, - ); - path = TopCoins; - sourceTree = ""; - }; 1A56463750A2B2C557B399E7 /* Security */ = { isa = PBXGroup; children = ( @@ -7254,26 +6860,6 @@ path = Security; sourceTree = ""; }; - 1A5646D7F9188134B80B17F2 /* TopPlatforms */ = { - isa = PBXGroup; - children = ( - 11B3582259AD3A0C55CF6D2C /* MarketOverviewTopPlatformsService.swift */, - 1A56477F6FC71270AD53A3AE /* MarketOverviewTopPlatformsViewModel.swift */, - 1A564B44985D1169593F202C /* MarketOverviewTopPlatformsDataSource.swift */, - ); - path = TopPlatforms; - sourceTree = ""; - }; - 1A5646DA41E1060F8643C9C0 /* GlobalMarket */ = { - isa = PBXGroup; - children = ( - 1A564EDF0FD6A1D1575D1EFB /* MarketOverviewGlobalService.swift */, - 1A5649C48B3AABC56D2512ED /* MarketOverviewGlobalViewModel.swift */, - 1A5647FA18CC69113ECB6581 /* MarketOverviewGlobalDataSource.swift */, - ); - path = GlobalMarket; - sourceTree = ""; - }; 1A5646EF1FF04ABE198C069D /* Placeholder */ = { isa = PBXGroup; children = ( @@ -7293,19 +6879,6 @@ path = ScanQr; sourceTree = ""; }; - 1A56485634872CA2E6CFD6EE /* TopPlatform */ = { - isa = PBXGroup; - children = ( - 1A564BDA5600859626D99BB4 /* TopPlatformModule.swift */, - 1A5649C0BD100768C726B4FB /* TopPlatformService.swift */, - 1A564A1B86DF22E86F0BB442 /* TopPlatformMarketCapFetcher.swift */, - 11B3527F1528AA697AAA6E61 /* TopPlatformViewModel.swift */, - 11B357E05A8AF5608ECF5D5F /* TopPlatformHeaderCell.swift */, - 11B35BB370AE2C896BB9F877 /* TopPlatformViewController.swift */, - ); - path = TopPlatform; - sourceTree = ""; - }; 1A5648A0CFE0BED4703D9794 /* Privacy */ = { isa = PBXGroup; children = ( @@ -7343,19 +6916,6 @@ path = AppStatus; sourceTree = ""; }; - 1A564F308577D43053000DE8 /* MarketNftTopCollections */ = { - isa = PBXGroup; - children = ( - 1A564E5282C3C22DA85141AF /* MarketNftTopCollectionsModule.swift */, - 1A564D12426BCA027C67377E /* MarketNftTopCollectionsService.swift */, - 1A5649E41FE690AF0A712426 /* MarketNftTopCollectionsViewModel.swift */, - 1A5641A724199908970CFB54 /* MarketNftTopCollectionsViewController.swift */, - 1A564CC5878BF33B8CE1F339 /* MarketListNftCollectionDecorator.swift */, - 1A5643A672A508BC4CBCABDD /* NftCollectionsMultiSortHeaderViewModel.swift */, - ); - path = MarketNftTopCollections; - sourceTree = ""; - }; 2FA5D04441C8926DBEB858AF /* InputOutputOrder */ = { isa = PBXGroup; children = ( @@ -7592,17 +7152,6 @@ path = Address; sourceTree = ""; }; - 58AAA113A485122CE8DBE7B4 /* MarketPosts */ = { - isa = PBXGroup; - children = ( - 58AAA42A6EB5242006547A92 /* MarketPostModule.swift */, - 58AAA657E30EBD52A5E06ACF /* MarketPostService.swift */, - 58AAA11651E3CE29A461BF42 /* MarketPostViewModel.swift */, - 58AAA263DAB58FD63E6A9351 /* MarketPostViewController.swift */, - ); - path = MarketPosts; - sourceTree = ""; - }; 58AAA1A28E8F61C815C86131 /* Info */ = { isa = PBXGroup; children = ( @@ -7682,22 +7231,6 @@ path = Fiat; sourceTree = ""; }; - 58AAA3EE50F55E115BCF90B6 /* Views */ = { - isa = PBXGroup; - children = ( - 58AAAA3930D3CB65CC545658 /* GradientPercentCircle.swift */, - 58AAA50A504CFA74CA19A415 /* MarketMetricView.swift */, - 11B3503B9A985B4835FDB03D /* MarketMultiSortHeaderView.swift */, - 11B350FAB6F1A6E1FCFACB2F /* MarketMultiSortHeaderViewModel.swift */, - 58AAA15F4FA7B9EC091EDFF3 /* MarketSingleSortHeaderView.swift */, - 58AAA51AD262FBDC3D69EEF8 /* MarketSingleSortHeaderViewModel.swift */, - 58AAA78BB269FEBB430092A3 /* MarketTvlSortHeaderViewModel.swift */, - 58AAA4A4F31EAB9164B33299 /* MarketTvlSortHeaderView.swift */, - 11B35F9BA41AC15436A4B977 /* DropdownSortHeaderView.swift */, - ); - path = Views; - sourceTree = ""; - }; 58AAA5B7985B3E7423CFD479 /* OneInch */ = { isa = PBXGroup; children = ( @@ -7707,26 +7240,6 @@ path = OneInch; sourceTree = ""; }; - 58AAA5C5DA041F3A46A6B241 /* MarketOverview */ = { - isa = PBXGroup; - children = ( - 1A5646DA41E1060F8643C9C0 /* GlobalMarket */, - 1A5645A040DB85EC7ED82369 /* TopCoins */, - 1A56441B781D474BC4F6FA85 /* Category */, - 1A5646D7F9188134B80B17F2 /* TopPlatforms */, - 3AB682BC25BADD97002197A5 /* MarketOverviewModule.swift */, - 1A564206FEC56546760B9BEA /* MarketOverviewViewModel.swift */, - 1A5644E4694DBB0E6E0B10CC /* BaseMarketOverviewTopListDataSource.swift */, - 58AAAFB549AE163AD4F920DD /* MarketOverviewViewController.swift */, - 58AAA2521E8F8845D96AB865 /* MarketOverviewHeaderCell.swift */, - 11B35DCCC2D8CD00EF6A9A77 /* MarketOverviewMetricsCell.swift */, - 11B3554159E6E5B7C1E71F04 /* MarketOverviewService.swift */, - 11B35DB992C240A4CF24938A /* MarketCategoryView.swift */, - 11B352D7FBB7101D346C9CCF /* TopPairs */, - ); - path = MarketOverview; - sourceTree = ""; - }; 58AAA7A159BA985AD4DB5515 /* Views */ = { isa = PBXGroup; children = ( @@ -7747,15 +7260,6 @@ path = CoinChart; sourceTree = ""; }; - 58AAA8784275769B6BEF45F5 /* MarketGlobal */ = { - isa = PBXGroup; - children = ( - 58AAA0A9EA8A2210522F38EE /* MarketGlobalFetcher.swift */, - 58AAA7D7F06F7C044DF9CE0A /* MarketGlobalModule.swift */, - ); - path = MarketGlobal; - sourceTree = ""; - }; 58AAA88E3D2A68E24195C0C3 /* ViewModels */ = { isa = PBXGroup; children = ( @@ -7781,6 +7285,10 @@ 58AAA9EB9618EBC895D0B123 /* Market */ = { isa = PBXGroup; children = ( + D3EE4A462C0EEE7100E40C97 /* Tab */, + D3EE4A452C0EEE6500E40C97 /* Global */, + D3EE4A442C0EEE5700E40C97 /* Search */, + D3EE4A432C0EE43000E40C97 /* Fetchers */, D3D13A5D2C0D9D9A002484BC /* AdvancedSearch */, 6BB14F782C05FAA600E879B2 /* Tvl */, D3384D1F2BFF0CBD00515664 /* Volume */, @@ -7792,31 +7300,8 @@ D3833ADC2BEE3FC200ACECFB /* Platforms */, D3833AD52BEE1A2900ACECFB /* Watchlist */, D3DB51AD2BD7A9740091BBDB /* Coins */, - 11B35AAFE626B8D1806D8960 /* MarketList */, - 58AAA5C5DA041F3A46A6B241 /* MarketOverview */, - 58AAAAF9DC549506AF5B4C6D /* MarketWatchlist */, - 58AAA8784275769B6BEF45F5 /* MarketGlobal */, - 58AAA113A485122CE8DBE7B4 /* MarketPosts */, - 11B3508440D2593C95D34386 /* MarketCategory */, - 11B353B7A5F3850C328543E8 /* MarketTop */, - 58AAAC5B31C9DD58D57A3EA9 /* MarketGlobalMetric */, - 58AAA3EE50F55E115BCF90B6 /* Views */, - 1A564F308577D43053000DE8 /* MarketNftTopCollections */, - 1A56459494751BD5A4416ECB /* MarketTopPlatforms */, - 1A56485634872CA2E6CFD6EE /* TopPlatform */, 58AAA3173853A16B2433AEC0 /* MarketModule.swift */, - 58AAAA9DFF1F23B0B8A8CEAD /* MarketViewModel.swift */, - 58AAA8FDCCC09B609C7D0FEA /* MarketViewController.swift */, - 11B3543F4D196A47EFE3E6F7 /* MarketHeaderCell.swift */, - 11B3546A0ED6C1FCC3C5A097 /* FilteredList */, - 11B35022BB7BE673C5108390 /* MarketTopPairs */, D311DA1B2BD114B00013DB8F /* MarketView.swift */, - D311DA1E2BD115240013DB8F /* MarketGlobalViewModel.swift */, - D3DB51982BD63D680091BBDB /* MarketSearchViewModel.swift */, - D3DB519E2BD6854A0091BBDB /* MarketSearchView.swift */, - D3DB51A12BD6857E0091BBDB /* MarketGlobalView.swift */, - D3DB51A42BD685B40091BBDB /* MarketTabView.swift */, - D3833B012BF38A8000ACECFB /* MarketTabViewModel.swift */, ); path = Market; sourceTree = ""; @@ -7847,18 +7332,6 @@ path = OneInch; sourceTree = ""; }; - 58AAAAF9DC549506AF5B4C6D /* MarketWatchlist */ = { - isa = PBXGroup; - children = ( - 58AAA7D27615D192FBC5486E /* MarketWatchlistModule.swift */, - 58AAABDFE887324FC10AC290 /* MarketWatchlistService.swift */, - 11B3566FE007887C3528583C /* MarketWatchlistViewModelOld.swift */, - 58AAAA1B62A6A1A278BE06AA /* MarketWatchlistViewController.swift */, - ABC9A8B6A5C590B23C6F83C3 /* MarketWatchlistDecorator.swift */, - ); - path = MarketWatchlist; - sourceTree = ""; - }; 58AAAB6A314C9C062F5707AB /* Debug */ = { isa = PBXGroup; children = ( @@ -7879,29 +7352,6 @@ path = DoubleSpendInfo; sourceTree = ""; }; - 58AAAC23B9A9A22F8C485881 /* DefiCap */ = { - isa = PBXGroup; - children = ( - 58AAAD81E45666E783B8B2EA /* MarketGlobalDefiMetricService.swift */, - 58AAAFE702C2E51EEE209C56 /* MarketListDefiDecorator.swift */, - ); - path = DefiCap; - sourceTree = ""; - }; - 58AAAC5B31C9DD58D57A3EA9 /* MarketGlobalMetric */ = { - isa = PBXGroup; - children = ( - 6BB14F702BFE54F200E879B2 /* Etf */, - 58AAA7B3EA0C8B9FDEC41837 /* MarketGlobalMetricService.swift */, - 58AAA775FE9B46DA2910F508 /* MarketGlobalMetricModule.swift */, - 58AAA02D981360FF0CC50A19 /* MarketGlobalMetricViewController.swift */, - 58AAAC23B9A9A22F8C485881 /* DefiCap */, - 58AAADC5A7211A14D2E41B6C /* TvlInDefi */, - D311DA272BD27F5F0013DB8F /* MarketGlobalMetricsView.swift */, - ); - path = MarketGlobalMetric; - sourceTree = ""; - }; 58AAAC89F3E7CD9F799B89D7 /* Coin */ = { isa = PBXGroup; children = ( @@ -7922,7 +7372,6 @@ 58AAA353DAC061C2123948FC /* CoinPageViewController.swift */, 58AAA55A4A6A97C25F84034F /* CoinChartFactory.swift */, 58AAA444C885BCC354F1B7B3 /* CoinPageMarkdownParser.swift */, - 11B354B9064677BDA5946B48 /* Ranks */, ABC9A04E5F5F2817B1E287A2 /* Indicators */, 11B3529DC8E74672659515B8 /* CoinPageViewModelNew.swift */, 11B3553967AFF40F6A9A611A /* CoinPageView.swift */, @@ -7930,17 +7379,6 @@ path = Coin; sourceTree = ""; }; - 58AAADC5A7211A14D2E41B6C /* TvlInDefi */ = { - isa = PBXGroup; - children = ( - 58AAA8E1106E31D68FD9181D /* MarketGlobalTvlMetricViewController.swift */, - 58AAADBB7B760C189AD6032F /* MarketGlobalTvlMetricService.swift */, - 58AAA9B26F62DB74FF3830D5 /* MarketListTvlDecorator.swift */, - 58AAAEA0582FFB81EB6C6263 /* MarketGlobalTvlFetcher.swift */, - ); - path = TvlInDefi; - sourceTree = ""; - }; 58AAAED208A8D02F3BC8B828 /* Adapters */ = { isa = PBXGroup; children = ( @@ -8015,14 +7453,6 @@ path = Rank; sourceTree = ""; }; - 6BB14F702BFE54F200E879B2 /* Etf */ = { - isa = PBXGroup; - children = ( - 6BB14F712BFE550600E879B2 /* MarketEtfFetcher.swift */, - ); - path = Etf; - sourceTree = ""; - }; 6BB14F782C05FAA600E879B2 /* Tvl */ = { isa = PBXGroup; children = ( @@ -9525,6 +8955,44 @@ path = Coins; sourceTree = ""; }; + D3EE4A432C0EE43000E40C97 /* Fetchers */ = { + isa = PBXGroup; + children = ( + 58AAA0A9EA8A2210522F38EE /* MarketGlobalFetcher.swift */, + 1A564A1B86DF22E86F0BB442 /* TopPlatformMarketCapFetcher.swift */, + 6BB14F712BFE550600E879B2 /* MarketEtfFetcher.swift */, + 58AAA7D7F06F7C044DF9CE0A /* MarketGlobalModule.swift */, + ); + path = Fetchers; + sourceTree = ""; + }; + D3EE4A442C0EEE5700E40C97 /* Search */ = { + isa = PBXGroup; + children = ( + D3DB51982BD63D680091BBDB /* MarketSearchViewModel.swift */, + D3DB519E2BD6854A0091BBDB /* MarketSearchView.swift */, + ); + path = Search; + sourceTree = ""; + }; + D3EE4A452C0EEE6500E40C97 /* Global */ = { + isa = PBXGroup; + children = ( + D311DA1E2BD115240013DB8F /* MarketGlobalViewModel.swift */, + D3DB51A12BD6857E0091BBDB /* MarketGlobalView.swift */, + ); + path = Global; + sourceTree = ""; + }; + D3EE4A462C0EEE7100E40C97 /* Tab */ = { + isa = PBXGroup; + children = ( + D3DB51A42BD685B40091BBDB /* MarketTabView.swift */, + D3833B012BF38A8000ACECFB /* MarketTabViewModel.swift */, + ); + path = Tab; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -9957,7 +9425,6 @@ 11B35D54818399B4BCE9F2C2 /* UnlinkViewController.swift in Sources */, D36DE0E5272FD887000BC916 /* OneInchService.swift in Sources */, 11B35F66D2561CD9555C8857 /* UnlinkModule.swift in Sources */, - 3A73FC9E258B1AF700FE4D34 /* MarketWatchlistModule.swift in Sources */, 11B35B99C84075296D6F26DE /* UnlinkViewModel.swift in Sources */, 11B35177B650540BCEA880B3 /* UnlinkService.swift in Sources */, 1A5645335BEED7A26D53A6B9 /* AddressUri.swift in Sources */, @@ -9966,7 +9433,6 @@ 1A56475828E9121D78E02D67 /* BitcoinCashAdapter.swift in Sources */, 11B352E00B6E0DF4F6D42486 /* DashAdapter.swift in Sources */, 11B359F074038D1507C23747 /* EnabledWallet.swift in Sources */, - 3A73FCB1258B1AFD00FE4D34 /* GradientPercentCircle.swift in Sources */, 11B358B0576F63BE43947DD5 /* Account.swift in Sources */, 11B35BEB439509EACB41AB06 /* AccountType.swift in Sources */, 11B35F663F7E12BFDDE3C88B /* AccountManager.swift in Sources */, @@ -9996,7 +9462,6 @@ D003297726CD2C67002EC21D /* TransactionLockInfo.swift in Sources */, 2FA5DB3B49EF898B63DD0F94 /* KitCleaner.swift in Sources */, 2FA5D98D7EE8F90744430243 /* TimeInterval.swift in Sources */, - 3AB682BF25BADD97002197A5 /* MarketOverviewModule.swift in Sources */, 11B3538BB9A4C913033D250F /* FeeCoinProvider.swift in Sources */, D02A67BD272A7460009B2C1C /* TweetCell.swift in Sources */, 11B3527D20636D21F0F45C80 /* CurrentDateProvider.swift in Sources */, @@ -10014,7 +9479,6 @@ 58AAAD3A237C3A2F46FD2509 /* DebugPresenter.swift in Sources */, 58AAA0BEEC3EF61DCB80C6BA /* DebugViewController.swift in Sources */, 58AAAD3AC2B87E6AAFE535D8 /* DebugLogger.swift in Sources */, - 3A73FCAE258B1AFD00FE4D34 /* MarketMetricView.swift in Sources */, 1A564EDBD3E4B37299E199B7 /* AppStatusModule.swift in Sources */, 11B3557CB2595D2884C94498 /* MultiTextMetricsView.swift in Sources */, 1A564F73B7FE144D39DEA34F /* UIDevice.swift in Sources */, @@ -10058,7 +9522,6 @@ D36DE0C1272FD864000BC916 /* UniswapService.swift in Sources */, 11B35CB5A90FCD0B53D59140 /* AlertViewController.swift in Sources */, 11B35C8A76BB5C69263E9757 /* AlertModule.swift in Sources */, - 3A73FC7A258B1AE500FE4D34 /* MarketViewModel.swift in Sources */, 11B35383F24853BDDB27618A /* AlertPresenter.swift in Sources */, 11B35D835774B7F4E286BF32 /* AlertRouter.swift in Sources */, 11B35996BB3F179501DC0B08 /* BottomSheetTitleView.swift in Sources */, @@ -10107,7 +9570,6 @@ 11B3533941A80D693369E9C0 /* BrandFooterCell.swift in Sources */, 58AAAAF8C20AB0E0299A36B8 /* CoinSelectModule.swift in Sources */, 58AAA9AEFE1043B01BEC2D6A /* CoinSelectViewController.swift in Sources */, - 3A73FC75258B1ADB00FE4D34 /* MarketViewController.swift in Sources */, 58AAA8CECD9281330BE789B8 /* InfoViewController.swift in Sources */, 58AAA410C9996BA929E3CEEF /* InfoModule.swift in Sources */, D05E96982A262149002CCD71 /* TronTransactionRecord.swift in Sources */, @@ -10164,7 +9626,6 @@ D0A980B02B60E73F00127AF4 /* LegacyFeeSettingsView.swift in Sources */, D0C226142A66A3DB007101F7 /* PersonalSupportViewController.swift in Sources */, 11B35A4D9BD4B8C29FBAFACF /* AboutModule.swift in Sources */, - 3A73FC9C258B1AF700FE4D34 /* MarketWatchlistViewController.swift in Sources */, 11B35B086B0D62A9D7A10CD0 /* AddTokenViewModel.swift in Sources */, 11B35A42BF19B93C6005FBD9 /* AddTokenService.swift in Sources */, 11B35D550563934444558D15 /* AddTokenViewController.swift in Sources */, @@ -10189,8 +9650,6 @@ 11B354B34C4B6471F67F5471 /* InputPrefixWrapperView.swift in Sources */, D3DD67352BC3CC2100EC7F78 /* ThorChainMultiSwapBtcQuote.swift in Sources */, 11B35A42D28B8BC4CDA57D8E /* AccountRecord_v_0_19.swift in Sources */, - 58AAAA8975F5B63340672D00 /* MarketWatchlistService.swift in Sources */, - 11B35B970E8949F968960796 /* MarketListViewController.swift in Sources */, D0E659BC2B875003000D8981 /* ResendBitcoinViewModel.swift in Sources */, 11B35B501A30615698B04C96 /* AddEvmTokenBlockchainService.swift in Sources */, 11B35E57C6406D2249A23E6F /* SendEvmTransactionService.swift in Sources */, @@ -10301,7 +9760,6 @@ 11B354EFE4620A8E65D44335 /* WalletViewModel.swift in Sources */, 11B35E5DDFA437BD43717962 /* WalletViewController.swift in Sources */, 11B352C447693BA4688A9673 /* WalletModule.swift in Sources */, - 505E7F742897C6DA00229BF2 /* TopPlatformService.swift in Sources */, 11B35A5CCED22BDE4C93CE23 /* WalletBlockchainElementService.swift in Sources */, 11B350B3D287EE732007892B /* WalletCoinPriceService.swift in Sources */, 11B355EBC83D70F2D41D9217 /* WalletViewItemFactory.swift in Sources */, @@ -10339,9 +9797,7 @@ D3DB51B32BD912A00091BBDB /* MarketInfo.swift in Sources */, 11B3598D4F303310AC88FE90 /* BaseCurrencySettingsModule.swift in Sources */, D023D26E2A24CD4F004F65B0 /* TronKitManager.swift in Sources */, - 58AAAAED41A83519EFB94237 /* MarketPostViewModel.swift in Sources */, D00267BD2A57E72700D6B2D5 /* ResendPasteInputView.swift in Sources */, - 58AAA3FE5DE72D3CEFFE4399 /* MarketPostService.swift in Sources */, 1A564CFD8F22A2F5FDB346EA /* JailbreakService.swift in Sources */, D3833AFD2BF335C700ACECFB /* MarketNewsView.swift in Sources */, D05E96A72A2627E5002CCD71 /* TronOutgoingTransactionRecord.swift in Sources */, @@ -10457,39 +9913,15 @@ 11B358362F756E91646878D0 /* CoinValue.swift in Sources */, 2FA5D7CDF884D2655E066C3E /* TransactionValue.swift in Sources */, 58AAA3F0AFD0D0F5FCD24DEF /* SelectorButton.swift in Sources */, - 58AAAF886ADA156E5559EE5B /* MarketOverviewViewController.swift in Sources */, - 58AAA1B716FCD40947F4F95C /* MarketOverviewHeaderCell.swift in Sources */, - 58AAAAEC33A43B54E8E4D3FB /* MarketPostViewController.swift in Sources */, D05E969B2A26278D002CCD71 /* TronApproveTransactionRecord.swift in Sources */, - 58AAA5EF1B46CAFB40139AD2 /* MarketPostModule.swift in Sources */, - 11B35EC2E4E5614FF64C7246 /* MarketMultiSortHeaderView.swift in Sources */, 2FA5D4C4D13E610DA6009C48 /* CoinOverviewViewModel.swift in Sources */, D05E969E2A2627AF002CCD71 /* TronContractCallTransactionRecord.swift in Sources */, 2FA5D72F396BC5D16C228112 /* CoinOverviewService.swift in Sources */, 2FA5DF327EC188AC29719179 /* CoinOverviewModule.swift in Sources */, 2FA5D0F37E1B46988A88DB29 /* CoinOverviewViewController.swift in Sources */, - 11B35CD199C820EC89FBB546 /* MarketListViewModel.swift in Sources */, - 11B356CF55DB1BE22071B24E /* MarketMultiSortHeaderViewModel.swift in Sources */, - 11B352E46C24498018071705 /* MarketCategoryService.swift in Sources */, - 11B35664B1EDEAB99B7B51AE /* MarketCategoryModule.swift in Sources */, - 11B358F9D6842ECD84E80752 /* MarketCategoryViewModel.swift in Sources */, - 11B35DFCEC1D363B160479EE /* MarketTopService.swift in Sources */, 6B2907262AF0CB8A006157D6 /* WalletConnectAppShowView.swift in Sources */, - 11B35A5A820C1BCC1A92E944 /* MarketTopViewController.swift in Sources */, - 11B35A8BB87C68ACF4594C99 /* MarketTopModule.swift in Sources */, - 11B35FF6D36153F372C16C32 /* MarketWatchlistViewModelOld.swift in Sources */, - 58AAA488935A7DE6CF7C592D /* MarketGlobalMetricService.swift in Sources */, - 58AAA7B0CC093B05F7487496 /* MarketGlobalMetricModule.swift in Sources */, - 58AAA937A06DD40BD9A64C71 /* MarketGlobalMetricViewController.swift in Sources */, - 58AAAB9BE155C6F7630BCE31 /* MarketSingleSortHeaderView.swift in Sources */, - 58AAA76E5789D2C9EAC9A2B6 /* MarketSingleSortHeaderViewModel.swift in Sources */, D00DAE462B626C2900F48E1D /* GasPrice.swift in Sources */, - 11B35C2ED09C6D5660BB1236 /* MarketWatchlistToggleService.swift in Sources */, - 11B35F28C21E228AB3158716 /* MarketOverviewMetricsCell.swift in Sources */, D36DE0AC272FD612000BC916 /* SwapViewController.swift in Sources */, - 11B350F36947CF278CDB436B /* MarketListMarketFieldDecorator.swift in Sources */, - 58AAACF322E073F1DDA1FBDC /* MarketTvlSortHeaderViewModel.swift in Sources */, - 58AAAF56EF620164D797D60F /* MarketTvlSortHeaderView.swift in Sources */, D087627729815DAE00E6FFD4 /* ChooseWatchViewModel.swift in Sources */, 11B358E508ECA92493A9A3FD /* CoinPageService.swift in Sources */, 11B35FBC1AFDCF0DB8362C88 /* CoinAnalyticsModule.swift in Sources */, @@ -10508,19 +9940,12 @@ 11B35B925CE6EB25DF542611 /* CoinInvestorsService.swift in Sources */, 6BCD53052A161F4100993F20 /* ICloudBackupTermsViewController.swift in Sources */, 11B354FA6F6BF59F64560590 /* CoinTreasuriesViewModel.swift in Sources */, - 11B35F3C9850408B9ADE0B16 /* DropdownSortHeaderView.swift in Sources */, 11B351A2A88DF7E8BEF88DB0 /* CoinReportsViewController.swift in Sources */, 11B35E48433E1F44C3D3886C /* CoinReportsModule.swift in Sources */, 11B356A19A721D3557D7213C /* CoinReportsViewModel.swift in Sources */, 11B3547D1AEE88F583C3E5E5 /* CoinReportsService.swift in Sources */, 11B35F6092E0950714E277E4 /* PostCell.swift in Sources */, - 58AAAEA69AA123E96665E2B7 /* MarketGlobalDefiMetricService.swift in Sources */, D054DAE42BE5123F0040B7C9 /* InitialTransactionSettings.swift in Sources */, - 58AAAB25F7EDB3EAE26E690C /* MarketGlobalTvlMetricViewController.swift in Sources */, - 58AAA4C8FEC03BAFB1B4863E /* MarketGlobalTvlMetricService.swift in Sources */, - 58AAA60557D3A9E3AE7372E0 /* MarketListDefiDecorator.swift in Sources */, - 58AAAA07DC05EF7F912EA184 /* MarketListTvlDecorator.swift in Sources */, - 58AAAFC5FE754A2286161D16 /* MarketGlobalTvlFetcher.swift in Sources */, 11B354283B8AC609B65AADDF /* FavoriteCoinRecord_v_0_38.swift in Sources */, 6BA5117E2BCFA06F00CB5A54 /* FirstAppearModifier.swift in Sources */, 58AAAD1BFFE70A777DDF27A9 /* AddressParserChain.swift in Sources */, @@ -10579,7 +10004,6 @@ ABC9AE6D877341985A6F651F /* SendBitcoinAmountInputService.swift in Sources */, ABC9A62EF59AF658C1DAD36F /* SendAmountCautionService.swift in Sources */, ABC9AF77EF53B4A7B0C0E55A /* SendAmountCautionViewModel.swift in Sources */, - 1A564CC4790F0CED826C131F /* MarketOverviewViewModel.swift in Sources */, 11B359C198AA7A141522E5E9 /* EvmAccountManagerFactory.swift in Sources */, 6BB14F7E2C05FBB000E879B2 /* MarketTvlView.swift in Sources */, 11B350918797E615D4FF6677 /* BlockchainSettingRecordStorage.swift in Sources */, @@ -10629,17 +10053,8 @@ 11B358033DAB0FF23CF0E309 /* NftActivityService.swift in Sources */, 11B3584017622E1F2B3BA464 /* NftAssetButtonCell.swift in Sources */, 11B353B085BD167026DE4B5B /* CustomToken.swift in Sources */, - 1A564BC7CE38935CD443C235 /* MarketOverviewTopCoinsDataSource.swift in Sources */, - 1A56405536E22BFF69EE9593 /* MarketOverviewTopCoinsViewModel.swift in Sources */, 6B29072A2AF0CB8A006157D6 /* EventHandler.swift in Sources */, - 1A564E1912184BFC886548D9 /* MarketOverviewCategoryDataSource.swift in Sources */, - 1A564C6CCA15813506F20561 /* MarketOverviewCategoryViewModel.swift in Sources */, - 1A5640D097E24A155C1F2E56 /* MarketOverviewCategoryCell.swift in Sources */, D3A580982BE8AA90003953F4 /* BitcoinSendSettingsViewModel.swift in Sources */, - 1A564335057D41EECDC8021B /* MarketOverviewTopCoinsService.swift in Sources */, - 1A5648AB801E8DAA9B3D288E /* MarketOverviewGlobalService.swift in Sources */, - 1A5645CA87E32639CEE6681F /* MarketOverviewGlobalViewModel.swift in Sources */, - 1A5642348A701CF7CF5CD805 /* MarketOverviewGlobalDataSource.swift in Sources */, D3F9B02C2BE3A9A1009FFA95 /* MultiSwapSendView.swift in Sources */, 6B5F5E162C0DDD7500E03EB2 /* RankView.swift in Sources */, ABC9AB3DAD30AA400DEB719C /* SendBitcoinService.swift in Sources */, @@ -10663,13 +10078,6 @@ ABC9A55FD66CB6374F2D520D /* SendZcashViewController.swift in Sources */, ABC9A852D667D38030B7EF39 /* SendConfirmationModule.swift in Sources */, ABC9A4BD4CA7A7872CE6167E /* BaseSendViewController.swift in Sources */, - 1A5645A90CB5AAEF02745AC7 /* MarketNftTopCollectionsModule.swift in Sources */, - 1A56499414D2E3BBFF260D14 /* MarketNftTopCollectionsService.swift in Sources */, - 1A5644FA9A9599F94EE16916 /* MarketNftTopCollectionsViewModel.swift in Sources */, - 1A564BC0945C7CA8330A604E /* MarketNftTopCollectionsViewController.swift in Sources */, - 1A564C13834A2EE853542795 /* MarketListNftCollectionDecorator.swift in Sources */, - 1A564DFD9A3B16E7DA518F67 /* NftCollectionsMultiSortHeaderViewModel.swift in Sources */, - 1A564586DCCE6E87784B9E6E /* MarketListWatchViewModel.swift in Sources */, ABC9A78CFF8B232D330EC7B5 /* DiffLabel.swift in Sources */, ABC9ADE1C8B18509F080FD11 /* ProFeaturesStorage.swift in Sources */, ABC9AD565E3BAB7074D02D40 /* ProFeaturesAuthorizationAdapter.swift in Sources */, @@ -10684,23 +10092,10 @@ 11B35A5CD6B04D269E281A6A /* SyncerState.swift in Sources */, D3A580892BE4DAA2003953F4 /* EvmSendData.swift in Sources */, 11B35EE45B00510714693AA9 /* SyncerStateStorage.swift in Sources */, - 1A564C2E1B66C2C508F8327D /* MarketOverviewTopPlatformsViewModel.swift in Sources */, - 1A564D4581F280245579C9DF /* BaseMarketOverviewTopListDataSource.swift in Sources */, ABC9A2E921AE00E0AF5067DE /* CoinProChartModule.swift in Sources */, ABC9A32D8EFFA6779886A27A /* ProChartFetcher.swift in Sources */, - 1A564176DEB9ED375113DA3B /* MarketTopPlatformsModule.swift in Sources */, - 1A564EF252E8C535BEB0548B /* MarketTopPlatformsService.swift in Sources */, - 1A5640051485E3419FE674F1 /* MarketTopPlatformsViewModel.swift in Sources */, D3DB51B02BD7AF860091BBDB /* DiffText.swift in Sources */, - 1A564047000F9270ABC4AEC1 /* MarketTopPlatformsViewController.swift in Sources */, - 1A564EBD7F2BB47C7C209EC5 /* TopPlatformsMultiSortHeaderViewModel.swift in Sources */, - 1A56412970FD129426474522 /* MarketOverviewTopPlatformsDataSource.swift in Sources */, - 1A56417AE8B0F2513FC009A9 /* MarketListTopPlatformDecorator.swift in Sources */, ABC9AA8B7C29398895204651 /* ChartCell.swift in Sources */, - ABC9A7AF4EE29CDE045ADEF7 /* MarketCategoryMarketCapFetcher.swift in Sources */, - 11B355C8567EB1690E3BDA77 /* MarketOverviewService.swift in Sources */, - 11B359515EE181B7C3D773D3 /* MarketOverviewTopPlatformsService.swift in Sources */, - 11B357BF7588CB317EA62167 /* MarketOverviewCategoryService.swift in Sources */, ABC9A3187D032F44CD4E8986 /* MarketCardTitleView.swift in Sources */, ABC9AE553D422A163A09E5F8 /* MarketCardValueView.swift in Sources */, ABC9A19695087B66FD79ED99 /* Array.swift in Sources */, @@ -10756,7 +10151,6 @@ 11B3544E1538F4326C10A735 /* HeaderAmountView.swift in Sources */, ABC9A295A99F39EFAAF8FCDA /* Integer.swift in Sources */, ABC9A794E47FC07ABFC32BBD /* FeePriceScale.swift in Sources */, - 1A56443EA3671FA2A40F1F7E /* TopPlatformModule.swift in Sources */, 1A56463FADAB4646BA106A5D /* TopPlatformMarketCapFetcher.swift in Sources */, 11B35BADA9ACC9921545BAD9 /* SecondaryButtonCell.swift in Sources */, 11B357DDBC0536428B997FE5 /* InputSecondaryCircleButtonWrapperView.swift in Sources */, @@ -10960,19 +10354,8 @@ ABC9A2A9540003916929DC77 /* ContactBookSettingsModule.swift in Sources */, D3B73E2E2BDF6B6D0067429D /* MultiSwapSendHandler.swift in Sources */, ABC9A227648FF076E9518703 /* ContactBookHelper.swift in Sources */, - 11B353973C1ADD51D174AC74 /* CoinRankService.swift in Sources */, - 11B35B3F5DE4F73225EBFF36 /* CoinRankViewModel.swift in Sources */, - 11B35FA3A00690573A482BAC /* CoinRankViewController.swift in Sources */, - 11B35C81D9DFBF07955D2461 /* CoinRankModule.swift in Sources */, - 11B35A89B3F0D81C42DC5C40 /* CoinRankHeaderView.swift in Sources */, ABC9AEA4EF88D31D00781014 /* ContactLabelService.swift in Sources */, ABC9AC87FA11BA3478A8E801 /* TransactionsContactLabelService.swift in Sources */, - 11B351EEC95E342C2B4F5BC4 /* MarketHeaderCell.swift in Sources */, - 11B35CC691C53A0B870BB910 /* MarketFilteredListService.swift in Sources */, - 11B35C4A68DD7F7AF6DC4F27 /* TopPlatformViewModel.swift in Sources */, - 11B35E584C30C56AE18DE076 /* TopPlatformHeaderCell.swift in Sources */, - 11B35929AD3C9F27463392C6 /* TopPlatformViewController.swift in Sources */, - 11B35C83BC2D0EA7FF5B4832 /* MarketCategoryViewController.swift in Sources */, 11B356F39BE75B7663BBA399 /* Misc.swift in Sources */, ABC9A2746046C136F98F970A /* BackupContact.swift in Sources */, ABC9AE0D23A7B54521E77052 /* ECashAdapter.swift in Sources */, @@ -11315,7 +10698,6 @@ 11B35CC16ABA93A94F46FD5B /* SelectorButtonStyle.swift in Sources */, 11B35EB231893AFDD3A1FF5C /* PlaceholderViewNew.swift in Sources */, 11B3502E567C29F297090D9B /* SyncErrorView.swift in Sources */, - D311DA292BD27F5F0013DB8F /* MarketGlobalMetricsView.swift in Sources */, ABC9A5361D9712C95F456376 /* Extensions.swift in Sources */, D3DD672C2BC3BF5200EC7F78 /* OneInchMultiSwapConfirmationQuote.swift in Sources */, ABC9A50D63AD21802AF5DE22 /* BaseAnimation.swift in Sources */, @@ -11364,18 +10746,10 @@ ABC9A57D1DA5481E44DEE8C0 /* PrimaryCircleButtonStyle.swift in Sources */, ABC9A22690729B58621A1BBA /* InformedModifier.swift in Sources */, ABC9A8117EAF046CDD020077 /* BorderedEmptyCell.swift in Sources */, - 11B358946C5E7A72712EACB2 /* MarketCategoryView.swift in Sources */, 11B35AF710C287EB89018342 /* UIWindow.swift in Sources */, ABC9A341284773472DC4AF60 /* SecondaryActiveButtonStyle.swift in Sources */, D389BC472C0DCF4100724504 /* Advice.swift in Sources */, ABC9A582FAB4466B5B25E013 /* UsedAddressesView.swift in Sources */, - 11B3527103D25C72BC849651 /* MarketOverviewTopPairsDataSource.swift in Sources */, - 11B35D06FF4A25AF74553C36 /* MarketOverviewTopPairsViewModel.swift in Sources */, - 11B353E17EA348D431520FAD /* MarketListMarketPairDecorator.swift in Sources */, - 11B3543546FE55AE0AB91FAF /* MarketOverviewTopPairsService.swift in Sources */, - 11B353F04B500616AC5CB9C5 /* MarketTopPairsViewController.swift in Sources */, - 11B35FF14C4B775E570375EC /* MarketTopPairsViewModel.swift in Sources */, - 11B358634BEC799056209B93 /* MarketTopPairsModule.swift in Sources */, ABC9A9E7E67D0C8A7B2114B8 /* UnspentOutputsViewModel.swift in Sources */, D06B302D2B6A120E0012A161 /* LegacyFeeSettingsViewModel.swift in Sources */, ABC9A929CE4DC2F1569658D6 /* UnspentOutputsCell.swift in Sources */, @@ -11384,7 +10758,6 @@ ABC9AC726857BA4662F1CD72 /* BaseFiatService.swift in Sources */, ABC9A2C63884586EC3A6B508 /* AmountOutputSelectorViewModel.swift in Sources */, ABC9A4FB2D21F111ED63208D /* AddressOutputSelectorViewModel.swift in Sources */, - ABC9A160495EB67472B97E61 /* MarketWatchlistDecorator.swift in Sources */, ABC9A00DA1F4148859D9D1AB /* Eip1559FeeSettingsView.swift in Sources */, ABC9A252B1848D5A2E46C071 /* Eip1559FeeSettingsViewModel.swift in Sources */, 11B35E433AC4217552A8D668 /* MultiSwapView.swift in Sources */, @@ -11538,7 +10911,6 @@ 1A56491DC545ED4F8A6E6D40 /* Decimal.swift in Sources */, 11B35DE3E7E6EB3CFAB81329 /* UnlinkViewController.swift in Sources */, 11B350E34285A392F34198D0 /* UnlinkModule.swift in Sources */, - 3A73FC9B258B1AF700FE4D34 /* MarketWatchlistModule.swift in Sources */, 11B3555CA9B2F01358E055BE /* UnlinkViewModel.swift in Sources */, 11B35FB3A17F76325C98C2AB /* UnlinkService.swift in Sources */, 1A5648D075682B17EFE9CBB6 /* AddressUri.swift in Sources */, @@ -11548,7 +10920,6 @@ 11B3507DDEBA587C023CE898 /* DashAdapter.swift in Sources */, 11B3577193A4BD719E12CE2E /* EnabledWallet.swift in Sources */, 11B3588E8DA44A45661351D7 /* Account.swift in Sources */, - 3A73FCAD258B1AFC00FE4D34 /* GradientPercentCircle.swift in Sources */, 11B35A91D104DA35C08032B2 /* AccountType.swift in Sources */, 11B35068E05BC58C6C9A93D7 /* AccountManager.swift in Sources */, 11B35C8621E221DA1F157A5B /* AccountFactory.swift in Sources */, @@ -11576,7 +10947,6 @@ D02A67C5272A7460009B2C1C /* CoinTweetsViewModel.swift in Sources */, D36DE0C3272FD864000BC916 /* UniswapModule.swift in Sources */, 2FA5DDDD98533BAFCF3819C8 /* TimeInterval.swift in Sources */, - 3AB682BE25BADD97002197A5 /* MarketOverviewModule.swift in Sources */, 11B351B7666846080F31D976 /* FeeCoinProvider.swift in Sources */, 11B352184FCE4B2B3E68E459 /* CurrentDateProvider.swift in Sources */, 11B35AF1B38CDF6728158514 /* AppConfig.swift in Sources */, @@ -11594,7 +10964,6 @@ 58AAAF6248682EE23B3C3D5A /* DebugLogger.swift in Sources */, 1A5644CF2BEC2E7C6227BDC7 /* AppStatusModule.swift in Sources */, D05E96902A261D82002CCD71 /* TronTransactionAdapter.swift in Sources */, - 3A73FCAA258B1AFC00FE4D34 /* MarketMetricView.swift in Sources */, D05E96A32A2627DA002CCD71 /* TronIncomingTransactionRecord.swift in Sources */, 11B35D51B52EF0000711CE05 /* MultiTextMetricsView.swift in Sources */, 1A5647EF2A5B8141F0BE4320 /* UIDevice.swift in Sources */, @@ -11641,7 +11010,6 @@ D023D2672A24BBC6004F65B0 /* TronAddressParser.swift in Sources */, 11B35C16BE16B6AEEA0690EC /* AlertModule.swift in Sources */, 11B3557E460F3BA25ED9F6CC /* AlertPresenter.swift in Sources */, - 3A73FC78258B1AE500FE4D34 /* MarketViewModel.swift in Sources */, 11B35E81542268ACDC17502A /* AlertRouter.swift in Sources */, 11B35FC5D80CC1D4854DBC94 /* BottomSheetTitleView.swift in Sources */, 1A564F382602A283C370E7FB /* AppError.swift in Sources */, @@ -11692,7 +11060,6 @@ 11B356448BC036CD117EB7DC /* BrandFooterCell.swift in Sources */, 58AAA670C62548F1A92D680B /* CoinSelectModule.swift in Sources */, 58AAA1721028D6504074A158 /* CoinSelectViewController.swift in Sources */, - 3A73FC74258B1ADA00FE4D34 /* MarketViewController.swift in Sources */, 58AAA187A094370FA7CD2BDD /* InfoViewController.swift in Sources */, D05E96972A262149002CCD71 /* TronTransactionRecord.swift in Sources */, 58AAAE9383600A15C521DBD8 /* InfoModule.swift in Sources */, @@ -11746,7 +11113,6 @@ D0C226132A66A3DB007101F7 /* PersonalSupportViewController.swift in Sources */, 11B3550424326606B055D7E5 /* AboutModule.swift in Sources */, D0A980AF2B60E73F00127AF4 /* LegacyFeeSettingsView.swift in Sources */, - 3A73FC99258B1AF600FE4D34 /* MarketWatchlistViewController.swift in Sources */, 11B35959AAF414186CE39698 /* AddTokenViewModel.swift in Sources */, 11B35A90F19DE20ABE21F423 /* AddTokenService.swift in Sources */, 11B35FAB3263E489CB9017FC /* AddTokenViewController.swift in Sources */, @@ -11772,8 +11138,6 @@ 11B35FF65FCE441A69822E1C /* InputPrefixWrapperView.swift in Sources */, D3DD67342BC3CC2100EC7F78 /* ThorChainMultiSwapBtcQuote.swift in Sources */, 11B35C3AFFA5B40481AF15B9 /* AccountRecord_v_0_19.swift in Sources */, - 58AAA8D67EB6C19719BD760B /* MarketWatchlistService.swift in Sources */, - 11B35C8E09922F59B200E347 /* MarketListViewController.swift in Sources */, 11B3556FCACE2ECE022138DF /* AddEvmTokenBlockchainService.swift in Sources */, D0E659BB2B875003000D8981 /* ResendBitcoinViewModel.swift in Sources */, 11B355FAD0E7823AF5F8EC83 /* SendEvmTransactionService.swift in Sources */, @@ -11920,9 +11284,7 @@ 58AAA4109DE36F8934808DE0 /* MarketGlobalModule.swift in Sources */, 11B352840E06275F96EFFCDB /* BaseCurrencySettingsModule.swift in Sources */, D3DB51B22BD912A00091BBDB /* MarketInfo.swift in Sources */, - 58AAA25AF71DF84F42A27157 /* MarketPostViewModel.swift in Sources */, D023D26D2A24CD4F004F65B0 /* TronKitManager.swift in Sources */, - 58AAA2494D41B33DC091A3E6 /* MarketPostService.swift in Sources */, D00267BC2A57E72700D6B2D5 /* ResendPasteInputView.swift in Sources */, 1A56464440899E3299F79D32 /* JailbreakService.swift in Sources */, 58AAAE5341084CFA30D4832C /* CoinPageMarkdownParser.swift in Sources */, @@ -12043,40 +11405,16 @@ 11B351909FE0FA637B5B1EC5 /* CoinValue.swift in Sources */, 2FA5DE1250DA9D85CD9BF1A3 /* TransactionValue.swift in Sources */, 58AAA72230207B253E2153EA /* SelectorButton.swift in Sources */, - 58AAAB5D89B03B266A4F9B57 /* MarketOverviewViewController.swift in Sources */, - 58AAAB41ED4FC861D1C99AAC /* MarketOverviewHeaderCell.swift in Sources */, D36DE0E4272FD887000BC916 /* OneInchService.swift in Sources */, - 58AAA07B54F11F0DF5E3E876 /* MarketPostViewController.swift in Sources */, - 58AAA31D8AD811C0C5434426 /* MarketPostModule.swift in Sources */, - 11B35EF70120304F6D4F5561 /* MarketMultiSortHeaderView.swift in Sources */, D05E969A2A26278D002CCD71 /* TronApproveTransactionRecord.swift in Sources */, 2FA5D40FA7CAC1BA01C0B373 /* CoinOverviewViewModel.swift in Sources */, 2FA5DBE42827FF3D114DBF4B /* CoinOverviewService.swift in Sources */, 2FA5DF4BB73C12C8DDF42599 /* CoinOverviewModule.swift in Sources */, D05E969D2A2627AF002CCD71 /* TronContractCallTransactionRecord.swift in Sources */, 2FA5DF596B5EE00090E050D9 /* CoinOverviewViewController.swift in Sources */, - 11B3502DA4A2B869638AF4D8 /* MarketListViewModel.swift in Sources */, - 11B35CCC81AE83E1CBB61504 /* MarketMultiSortHeaderViewModel.swift in Sources */, - 11B353260AE7B998C07955E6 /* MarketCategoryService.swift in Sources */, D36DE0C9272FD864000BC916 /* UniswapProvider.swift in Sources */, - 11B3553109794AE192BF7591 /* MarketCategoryModule.swift in Sources */, - 11B354ECE594CE629BA46BE1 /* MarketCategoryViewModel.swift in Sources */, - 11B3504029EB87A32DB63666 /* MarketTopService.swift in Sources */, - 11B35A426FD3D729DEB89DEA /* MarketTopViewController.swift in Sources */, - 11B357405174FF9F9BEB3704 /* MarketTopModule.swift in Sources */, - 11B352712EC6F2C7F6965443 /* MarketWatchlistViewModelOld.swift in Sources */, - 58AAA2960B54658E2614D72E /* MarketGlobalMetricService.swift in Sources */, - 58AAA996622FCD647B51A3C5 /* MarketGlobalMetricModule.swift in Sources */, - 58AAA5C000029E9EB74C46C4 /* MarketGlobalMetricViewController.swift in Sources */, D00DAE452B626C2900F48E1D /* GasPrice.swift in Sources */, - 58AAA004F244AFFC352ADCEF /* MarketSingleSortHeaderView.swift in Sources */, - 58AAA35AF4F4454E0E9C7C60 /* MarketSingleSortHeaderViewModel.swift in Sources */, - 11B353CB3021FA5266D07607 /* MarketWatchlistToggleService.swift in Sources */, - 11B35F1152FB1004E554B922 /* MarketOverviewMetricsCell.swift in Sources */, D02A67D1272A7460009B2C1C /* TweetsPageResponse.swift in Sources */, - 11B35C5E7A90AA7B302EB0CD /* MarketListMarketFieldDecorator.swift in Sources */, - 58AAA08E3204C7E7326E1DF9 /* MarketTvlSortHeaderViewModel.swift in Sources */, - 58AAA626C0B12976749A948E /* MarketTvlSortHeaderView.swift in Sources */, 11B35411C817EDE73D4E6242 /* CoinPageService.swift in Sources */, D087627629815DAE00E6FFD4 /* ChooseWatchViewModel.swift in Sources */, 11B35ED9D5F95988E9335440 /* CoinAnalyticsModule.swift in Sources */, @@ -12097,21 +11435,14 @@ D0532CC42B149E450015DF40 /* WatchService.swift in Sources */, 6BCD53042A161F4100993F20 /* ICloudBackupTermsViewController.swift in Sources */, 11B35E99BBF6DCCA72BDA4D1 /* CoinTreasuriesViewModel.swift in Sources */, - 11B351F81CCF4675CBDAC9B0 /* DropdownSortHeaderView.swift in Sources */, D054DAE32BE5123F0040B7C9 /* InitialTransactionSettings.swift in Sources */, 11B354542A3E929C1A7924FD /* CoinReportsViewController.swift in Sources */, 11B35FB74A0FAB9385945628 /* CoinReportsModule.swift in Sources */, 11B35CB98E9934D0C8EB4F08 /* CoinReportsViewModel.swift in Sources */, 11B35E48AA074CB56CAC4A9C /* CoinReportsService.swift in Sources */, 11B35EBC08855AC0CDC0AF09 /* PostCell.swift in Sources */, - 58AAAAC777502E0C331C109F /* MarketGlobalDefiMetricService.swift in Sources */, 6BA5117D2BCFA06F00CB5A54 /* FirstAppearModifier.swift in Sources */, - 58AAA153DF6764D7FEA99D63 /* MarketGlobalTvlMetricService.swift in Sources */, - 58AAAEB0F729B839B9B99A04 /* MarketListDefiDecorator.swift in Sources */, - 58AAA331B4A743D9183F8449 /* MarketListTvlDecorator.swift in Sources */, - 58AAACA5A8EC9B2A3182395F /* MarketGlobalTvlFetcher.swift in Sources */, 11B35D16F2F7B8E11A771B18 /* FavoriteCoinRecord_v_0_38.swift in Sources */, - 11B35D46B65772A1CC17B099 /* MarketGlobalTvlMetricViewController.swift in Sources */, 58AAADEF6F21AED422D7B569 /* AddressParserChain.swift in Sources */, 58AAAC635552C279592F60F9 /* EvmAddressParserItem.swift in Sources */, D3DD672E2BC3C5C400EC7F78 /* ThorChainMultiSwapEvmQuote.swift in Sources */, @@ -12171,7 +11502,6 @@ ABC9A4B643D98FB95F431401 /* SendBitcoinAmountInputService.swift in Sources */, ABC9ABF99296DEA24FC5BFF0 /* SendAmountCautionService.swift in Sources */, ABC9AB1E703AE57DF856ECD9 /* SendAmountCautionViewModel.swift in Sources */, - 1A564E2897197EB14584A62E /* MarketOverviewViewModel.swift in Sources */, 11B3538CDAA5FE6682A661D0 /* EvmAccountManagerFactory.swift in Sources */, 11B35696E9CD808522BEFCD6 /* BlockchainSettingRecordStorage.swift in Sources */, 11B3581F4D975FC21B9A25F2 /* BtcBlockchainSettingsModule.swift in Sources */, @@ -12216,18 +11546,9 @@ 11B35AC60BE4DC210C3C2312 /* NftActivityService.swift in Sources */, 11B35DC513240DBF0C78ED92 /* NftAssetButtonCell.swift in Sources */, 11B351DDFD1A7BC393EFA6E1 /* CustomToken.swift in Sources */, - 1A56405B48462C0750A47ECA /* MarketOverviewTopCoinsDataSource.swift in Sources */, - 1A564A45605FA993F9680646 /* MarketOverviewTopCoinsViewModel.swift in Sources */, D3A580972BE8AA90003953F4 /* BitcoinSendSettingsViewModel.swift in Sources */, - 1A5649ADA72E39CE24BB64FC /* MarketOverviewCategoryDataSource.swift in Sources */, - 1A56470F4D18CCC43B85DEB3 /* MarketOverviewCategoryViewModel.swift in Sources */, - 1A564FC84916FF6D6224FB33 /* MarketOverviewCategoryCell.swift in Sources */, - 1A56405220ED225C0B973A7F /* MarketOverviewTopCoinsService.swift in Sources */, D3F9B02B2BE3A9A1009FFA95 /* MultiSwapSendView.swift in Sources */, 6B5F5E152C0DDD7100E03EB2 /* RankView.swift in Sources */, - 1A564A4CF522A7A959482AA6 /* MarketOverviewGlobalService.swift in Sources */, - 1A564F3C50FC28F2AF4AF4ED /* MarketOverviewGlobalViewModel.swift in Sources */, - 1A5643CB57594E84707686A3 /* MarketOverviewGlobalDataSource.swift in Sources */, ABC9A5CB5C5D56F50FE5F64C /* SendTimeLockErrorService.swift in Sources */, ABC9A9493F250B81E1152012 /* SendBitcoinService.swift in Sources */, ABC9A774500F8D8D3D9E04DD /* SendBitcoinAdapterService.swift in Sources */, @@ -12250,13 +11571,6 @@ ABC9AA85AC9DC60A08211D16 /* SendZcashViewController.swift in Sources */, ABC9A78D3A4267CAC0F5D0E8 /* SendConfirmationModule.swift in Sources */, ABC9A1D42EED3235129D810B /* BaseSendViewController.swift in Sources */, - 1A56444C8342498C892E931E /* MarketNftTopCollectionsModule.swift in Sources */, - 1A564240E0BC3E93EDB3BA22 /* MarketNftTopCollectionsService.swift in Sources */, - 1A56427F500823630D07E75D /* MarketNftTopCollectionsViewModel.swift in Sources */, - 1A564DCC65AA9EADE56F2B7F /* MarketNftTopCollectionsViewController.swift in Sources */, - 1A5643E2C1AB8F24605342A0 /* MarketListNftCollectionDecorator.swift in Sources */, - 1A5646322B606C56DFFA324A /* NftCollectionsMultiSortHeaderViewModel.swift in Sources */, - 1A56422231460374E3830E56 /* MarketListWatchViewModel.swift in Sources */, ABC9A69FA41A9BC474DD1915 /* DiffLabel.swift in Sources */, ABC9A96132AD85DD613EC773 /* ProFeaturesStorage.swift in Sources */, ABC9AEDCDECE827D610F025A /* ProFeaturesAuthorizationAdapter.swift in Sources */, @@ -12271,23 +11585,10 @@ 11B351DED0D2632D24084263 /* EvmUpdateStatus.swift in Sources */, 11B35E83437BEB5CCE342ACB /* SyncerState.swift in Sources */, 11B35E61083F8A098D458EBC /* SyncerStateStorage.swift in Sources */, - 1A5648701B55E09FD8E4585D /* MarketOverviewTopPlatformsViewModel.swift in Sources */, - 1A5647BB75003E8292C8144B /* BaseMarketOverviewTopListDataSource.swift in Sources */, ABC9A6D1C4EF73D4A8D6F3BD /* CoinProChartModule.swift in Sources */, D3DB51AF2BD7AF860091BBDB /* DiffText.swift in Sources */, ABC9AECE6AD4A9DEA41DDBD9 /* ProChartFetcher.swift in Sources */, - 1A5648ACF2A5B2F7420DA5F6 /* MarketTopPlatformsModule.swift in Sources */, - 1A564E08B4F6C5B1CDB121F6 /* MarketTopPlatformsService.swift in Sources */, - 1A56402D725D6AB0C4149066 /* MarketTopPlatformsViewModel.swift in Sources */, - 1A564A9E6FF0EB1C6F2AA102 /* MarketTopPlatformsViewController.swift in Sources */, - 1A5646E52D8DFADAA5ACFCAD /* TopPlatformsMultiSortHeaderViewModel.swift in Sources */, - 1A5643B0422BC87461CC25C5 /* MarketOverviewTopPlatformsDataSource.swift in Sources */, - 1A56418183EC6CB602873B51 /* MarketListTopPlatformDecorator.swift in Sources */, ABC9A59B465A9C59F93DFB96 /* ChartCell.swift in Sources */, - ABC9AD3276132B33F6045AFF /* MarketCategoryMarketCapFetcher.swift in Sources */, - 11B358122FE64E16EC25F095 /* MarketOverviewService.swift in Sources */, - 11B35D06C75228488867EB22 /* MarketOverviewTopPlatformsService.swift in Sources */, - 11B352A7A3457BBAF4BF704F /* MarketOverviewCategoryService.swift in Sources */, ABC9A9562DD283B6FCACBCF9 /* MarketCardTitleView.swift in Sources */, ABC9AC1BD5C95957726F8AE8 /* MarketCardValueView.swift in Sources */, ABC9ADE7C30F3F992FD9E1CC /* Array.swift in Sources */, @@ -12341,8 +11642,6 @@ 11B356FF5E5CC9AA34B89C86 /* HeaderAmountView.swift in Sources */, ABC9A7CBFDC0DF741E29EA44 /* Integer.swift in Sources */, ABC9A3D46AA7356763213BA6 /* FeePriceScale.swift in Sources */, - 1A564C1395A1264F1A9B3AB5 /* TopPlatformModule.swift in Sources */, - 1A5648B10B34B402167EEA84 /* TopPlatformService.swift in Sources */, 1A5640DE72AC306799695F48 /* TopPlatformMarketCapFetcher.swift in Sources */, D3F9B0252BE38AF1009FFA95 /* RegularSendView.swift in Sources */, 11B357D1A2BD673DAB7B4C61 /* SecondaryButtonCell.swift in Sources */, @@ -12543,19 +11842,8 @@ ABC9A359DB8C1A89269236CC /* ContactBookSettingsModule.swift in Sources */, D3B73E2D2BDF6B6D0067429D /* MultiSwapSendHandler.swift in Sources */, ABC9ABE2B6B19113D7C5EDA3 /* ContactBookHelper.swift in Sources */, - 11B35D96A814579F37BAD3D0 /* CoinRankService.swift in Sources */, - 11B359C2651DA1F00A3C613C /* CoinRankViewModel.swift in Sources */, - 11B35F9CC94DB2BC7B43BB59 /* CoinRankViewController.swift in Sources */, - 11B352D8DDF054073BC79FC2 /* CoinRankModule.swift in Sources */, - 11B35BCF9FFC93255EFB2774 /* CoinRankHeaderView.swift in Sources */, ABC9A20F6F7D5EA2A1A55A9E /* ContactLabelService.swift in Sources */, ABC9AC84790F5BEAA514C731 /* TransactionsContactLabelService.swift in Sources */, - 11B35D2B9A488D3382D8693D /* MarketHeaderCell.swift in Sources */, - 11B354CBCCB0FFD2FDBEE757 /* MarketFilteredListService.swift in Sources */, - 11B35D90644F7735556DB3D5 /* TopPlatformViewModel.swift in Sources */, - 11B354CC5E68F04E22D633D9 /* TopPlatformHeaderCell.swift in Sources */, - 11B35D1F6602B517D19D5C76 /* TopPlatformViewController.swift in Sources */, - 11B353E15F4A208D393C7262 /* MarketCategoryViewController.swift in Sources */, 11B3511A2036EBD9611B3434 /* Misc.swift in Sources */, ABC9A074995C051E714FAFAB /* BackupContact.swift in Sources */, ABC9AEF0A2ECD0E627AF065B /* ECashAdapter.swift in Sources */, @@ -12898,7 +12186,6 @@ 11B359330CB6A60E5960CEC2 /* CoinMarketsView.swift in Sources */, 11B3545B6D4BA7CC76ACB9D2 /* ThemeList.swift in Sources */, 11B359CF6F464D59295B7B31 /* SelectorButtonStyle.swift in Sources */, - D311DA282BD27F5F0013DB8F /* MarketGlobalMetricsView.swift in Sources */, 11B35DCCBE18D2F1F16C01C5 /* PlaceholderViewNew.swift in Sources */, D3DD672B2BC3BF5200EC7F78 /* OneInchMultiSwapConfirmationQuote.swift in Sources */, 11B35ED9F3C0EA3CCC4C0FF4 /* SyncErrorView.swift in Sources */, @@ -12949,19 +12236,11 @@ ABC9AD530352E51084B1B4B7 /* PrimaryCircleButtonStyle.swift in Sources */, ABC9A639040A77968B5D86B8 /* InformedModifier.swift in Sources */, ABC9AB982879DE0BAE6701EC /* BorderedEmptyCell.swift in Sources */, - 11B358F04D8F15D43CB2BAA6 /* MarketCategoryView.swift in Sources */, D389BC462C0DCF4100724504 /* Advice.swift in Sources */, 11B3580BC3B5D2CBC68854D2 /* UIWindow.swift in Sources */, 11B3505B911DD28AC464A694 /* BackupManagerViewModel.swift in Sources */, ABC9AFAB60E13F58DC2F3D5D /* SecondaryActiveButtonStyle.swift in Sources */, ABC9A70FE468AB48CFF63201 /* UsedAddressesView.swift in Sources */, - 11B35611F21D266215BD82A5 /* MarketOverviewTopPairsDataSource.swift in Sources */, - 11B35FEB268E7C6B085B56C9 /* MarketOverviewTopPairsViewModel.swift in Sources */, - 11B358F511E01944DA31FF7D /* MarketListMarketPairDecorator.swift in Sources */, - 11B35B02E53E6D7DDC12FC5D /* MarketOverviewTopPairsService.swift in Sources */, - 11B35577071CBB59D7692DE4 /* MarketTopPairsViewController.swift in Sources */, - 11B35C72EF5FB79182EAB119 /* MarketTopPairsViewModel.swift in Sources */, - 11B35CA725B9BAD70E40197F /* MarketTopPairsModule.swift in Sources */, ABC9A22DF26B2A8C66B723BC /* UnspentOutputsViewModel.swift in Sources */, D06B302C2B6A120E0012A161 /* LegacyFeeSettingsViewModel.swift in Sources */, ABC9A4AE1AE901132578CC28 /* UnspentOutputsCell.swift in Sources */, @@ -12970,7 +12249,6 @@ ABC9AA70F3B1EFA37CBB7011 /* BaseFiatService.swift in Sources */, ABC9A291506C14262275CE0E /* AmountOutputSelectorViewModel.swift in Sources */, ABC9AC10C743C53832289B8A /* AddressOutputSelectorViewModel.swift in Sources */, - ABC9A2DA629CF38FD7B893EC /* MarketWatchlistDecorator.swift in Sources */, ABC9A8310AFE013E16F3DBAC /* Eip1559FeeSettingsView.swift in Sources */, ABC9A1798D6E2E4C868DA366 /* Eip1559FeeSettingsViewModel.swift in Sources */, 11B3594BEB2E05413B0DB30F /* MultiSwapView.swift in Sources */, diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Storage/LocalStorage.swift b/UnstoppableWallet/UnstoppableWallet/Core/Storage/LocalStorage.swift index 5379ea3e18..cd2e4cdd08 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Storage/LocalStorage.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Storage/LocalStorage.swift @@ -17,7 +17,6 @@ class LocalStorage { private let keyUserChartIndicatorsSync = "user-chart-indicators" private let keyIndicatorsShown = "indicators-shown" private let keyTelegramSupportRequested = "telegram-support-requested" - private let keyNewMarketTabEnabled = "new-market-tab-enabled" private let keyNewSendEnabled = "new-send-enabled" private let userDefaultsStorage: UserDefaultsStorage @@ -94,11 +93,6 @@ extension LocalStorage { set { userDefaultsStorage.set(value: newValue, for: keyTelegramSupportRequested) } } - var newMarketTabEnabled: Bool { - get { userDefaultsStorage.value(for: keyNewMarketTabEnabled) ?? false } - set { userDefaultsStorage.set(value: newValue, for: keyNewMarketTabEnabled) } - } - var newSendEnabled: Bool { get { userDefaultsStorage.value(for: keyNewSendEnabled) ?? false } set { userDefaultsStorage.set(value: newValue, for: keyNewSendEnabled) } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/DefiCoin.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/DefiCoin.swift index 4dc6445a8a..490f47b8d4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/DefiCoin.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/DefiCoin.swift @@ -1,13 +1,16 @@ +import Foundation import MarketKit -extension DefiCoin: Hashable { +extension DefiCoin { var name: String { switch type { case let .defiCoin(name, _): return name case let .fullCoin(fullCoin): return fullCoin.coin.name } } +} +extension DefiCoin: Hashable { public static func == (lhs: DefiCoin, rhs: DefiCoin) -> Bool { lhs.uid == rhs.uid } diff --git a/UnstoppableWallet/UnstoppableWallet/Extensions/StatExtensions.swift b/UnstoppableWallet/UnstoppableWallet/Extensions/StatExtensions.swift index 573eacd604..3bd522e14f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Extensions/StatExtensions.swift +++ b/UnstoppableWallet/UnstoppableWallet/Extensions/StatExtensions.swift @@ -58,16 +58,6 @@ extension MarketModule.Tab { } } -extension MarketModule.TabOld { - var statTab: StatTab { - switch self { - case .overview: return .overview - case .posts: return .news - case .watchlist: return .watchlist - } - } -} - extension CoinPageModule.Tab { var statTab: StatTab { switch self { @@ -124,7 +114,7 @@ extension CoinProChartModule.ProChartType { } } -extension CoinRankModule.RankType { +extension RankViewModel.RankType { var statRankType: StatPage { switch self { case .cexVolume: return .coinRankCexVolume @@ -153,48 +143,6 @@ extension MarketModule.Top { } } -extension MarketModule.MarketTop { - var statMarketTop: StatMarketTop { - switch self { - case .top100: return .top100 - case .top200: return .top200 - case .top300: return .top300 - } - } -} - -extension MarketModule.PriceChangeType { - var statPeriod: StatPeriod { - switch self { - case .day: return .day1 - case .week: return .week1 - case .week2: return .week2 - case .month: return .month1 - case .month6: return .month6 - case .year: return .year1 - } - } -} - -extension MarketModule.MarketField { - var statField: StatField { - switch self { - case .marketCap: return .marketCap - case .volume: return .volume - case .price: return .price - } - } -} - -extension MarketModule.MarketPlatformField { - var statTvlChain: String { - switch self { - case .all: return "all" - default: return chain - } - } -} - extension MarketModule.SortBy { var statSortType: StatSortType { switch self { @@ -229,15 +177,6 @@ extension MarketModule.SortOrder { } } -extension MarketModule.MarketTvlField { - var statField: String { - switch self { - case .value: return "currency" - case .diff: return "percent" - } - } -} - extension MarketTvlViewModel.DiffType { var statField: String { switch self { @@ -285,30 +224,6 @@ extension WatchlistTimePeriod { } } -extension MarketModule.SortingField { - var statSortType: StatSortType { - switch self { - case .highestCap: return .highestCap - case .lowestCap: return .lowestCap - case .highestVolume: return .highestVolume - case .lowestVolume: return .lowestVolume - case .topGainers: return .topGainers - case .topLosers: return .topLosers - } - } -} - -extension MarketTopPlatformsModule.SortType { - var statSortType: StatSortType { - switch self { - case .highestCap: return .highestCap - case .lowestCap: return .lowestCap - case .topGainers: return .topGainers - case .topLosers: return .topLosers - } - } -} - extension LinkType { var statPage: StatPage { switch self { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewController.swift index 475d8994b3..89e2a950df 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Analytics/CoinAnalyticsViewController.swift @@ -375,7 +375,7 @@ class CoinAnalyticsViewController: ThemeViewController { } private func openTvlRank() { - let viewController = MarketGlobalMetricModule.tvlInDefiViewController() + let viewController = MarketTvlView().toViewController() parentNavigationController?.pushViewController(viewController, animated: true) } @@ -404,8 +404,8 @@ class CoinAnalyticsViewController: ThemeViewController { parentNavigationController?.present(viewController, animated: true) } - private func openRanks(type: CoinRankModule.RankType) { - let viewController = CoinRankModule.newView(type: type) + private func openRanks(type: RankViewModel.RankType) { + let viewController = RankView(type: type).toViewController() parentNavigationController?.present(viewController, animated: true) } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankView.swift index e01993c7f1..b10d3d1c1e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankView.swift @@ -5,15 +5,15 @@ import SwiftUI struct RankView: View { @StateObject var viewModel: RankViewModel @StateObject var watchlistViewModel: WatchlistViewModel - @Binding var isPresented: Bool + + @Environment(\.presentationMode) private var presentationMode @State private var presentedCoin: Coin? @State private var timePeriodSelectorPresented = false - init(isPresented: Binding, type: CoinRankModule.RankType) { + init(type: RankViewModel.RankType) { _viewModel = StateObject(wrappedValue: RankViewModel(type: type)) _watchlistViewModel = StateObject(wrappedValue: WatchlistViewModel(page: type.statRankType)) - _isPresented = isPresented } var body: some View { @@ -50,7 +50,7 @@ struct RankView: View { .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("button.close".localized) { - isPresented = false + presentationMode.wrappedValue.dismiss() } } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankViewModel.swift index 749f6a1cf9..aba377411b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Rank/RankViewModel.swift @@ -6,7 +6,7 @@ import MarketKit class RankViewModel: ObservableObject { private let marketKit = App.shared.marketKit private let currencyManager = App.shared.currencyManager - let type: CoinRankModule.RankType + let type: RankType private var cancellables = Set() private var tasks = Set() @@ -33,7 +33,7 @@ class RankViewModel: ObservableObject { } } - init(type: CoinRankModule.RankType) { + init(type: RankType) { self.type = type currencyManager.$baseCurrency @@ -180,56 +180,67 @@ extension RankMultiValue { } } -extension CoinRankModule.RankType { - var title: String { - switch self { - case .cexVolume: return "coin_analytics.cex_volume_rank".localized - case .dexVolume: return "coin_analytics.dex_volume_rank".localized - case .dexLiquidity: return "coin_analytics.dex_liquidity_rank".localized - case .address: return "coin_analytics.active_addresses_rank".localized - case .txCount: return "coin_analytics.transaction_count_rank".localized - case .holders: return "coin_analytics.holders_rank".localized - case .fee: return "coin_analytics.project_fee_rank".localized - case .revenue: return "coin_analytics.project_revenue_rank".localized +extension RankViewModel { + enum RankType { + case cexVolume + case dexVolume + case dexLiquidity + case address + case txCount + case holders + case fee + case revenue + + var title: String { + switch self { + case .cexVolume: return "coin_analytics.cex_volume_rank".localized + case .dexVolume: return "coin_analytics.dex_volume_rank".localized + case .dexLiquidity: return "coin_analytics.dex_liquidity_rank".localized + case .address: return "coin_analytics.active_addresses_rank".localized + case .txCount: return "coin_analytics.transaction_count_rank".localized + case .holders: return "coin_analytics.holders_rank".localized + case .fee: return "coin_analytics.project_fee_rank".localized + case .revenue: return "coin_analytics.project_revenue_rank".localized + } } - } - var description: String { - switch self { - case .cexVolume: return "coin_analytics.cex_volume_rank.description".localized - case .dexVolume: return "coin_analytics.dex_volume_rank.description".localized - case .dexLiquidity: return "coin_analytics.dex_liquidity_rank.description".localized - case .address: return "coin_analytics.active_addresses_rank.description".localized - case .txCount: return "coin_analytics.transaction_count_rank.description".localized - case .holders: return "coin_analytics.holders_rank.description".localized - case .fee: return "coin_analytics.project_fee_rank.description".localized - case .revenue: return "coin_analytics.project_revenue_rank.description".localized + var description: String { + switch self { + case .cexVolume: return "coin_analytics.cex_volume_rank.description".localized + case .dexVolume: return "coin_analytics.dex_volume_rank.description".localized + case .dexLiquidity: return "coin_analytics.dex_liquidity_rank.description".localized + case .address: return "coin_analytics.active_addresses_rank.description".localized + case .txCount: return "coin_analytics.transaction_count_rank.description".localized + case .holders: return "coin_analytics.holders_rank.description".localized + case .fee: return "coin_analytics.project_fee_rank.description".localized + case .revenue: return "coin_analytics.project_revenue_rank.description".localized + } } - } - var imageUid: String { - switch self { - case .cexVolume: return "cex_volume" - case .dexVolume: return "dex_volume" - case .dexLiquidity: return "dex_liquidity" - case .address: return "active_addresses" - case .txCount: return "trx_count" - case .holders: return "holders" - case .fee: return "fee" - case .revenue: return "revenue" + var imageUid: String { + switch self { + case .cexVolume: return "cex_volume" + case .dexVolume: return "dex_volume" + case .dexLiquidity: return "dex_liquidity" + case .address: return "active_addresses" + case .txCount: return "trx_count" + case .holders: return "holders" + case .fee: return "fee" + case .revenue: return "revenue" + } } - } - var sortingField: String { - switch self { - case .cexVolume: return "coin_analytics.cex_volume_rank.sorting_field".localized - case .dexVolume: return "coin_analytics.dex_volume_rank.sorting_field".localized - case .dexLiquidity: return "coin_analytics.dex_liquidity_rank.sorting_field".localized - case .address: return "coin_analytics.active_addresses_rank.sorting_field".localized - case .txCount: return "coin_analytics.transaction_count_rank.sorting_field".localized - case .holders: return "coin_analytics.holders_rank.sorting_field".localized - case .fee: return "coin_analytics.project_fee_rank.sorting_field".localized - case .revenue: return "coin_analytics.project_revenue_rank.sorting_field".localized + var sortingField: String { + switch self { + case .cexVolume: return "coin_analytics.cex_volume_rank.sorting_field".localized + case .dexVolume: return "coin_analytics.dex_volume_rank.sorting_field".localized + case .dexLiquidity: return "coin_analytics.dex_liquidity_rank.sorting_field".localized + case .address: return "coin_analytics.active_addresses_rank.sorting_field".localized + case .txCount: return "coin_analytics.transaction_count_rank.sorting_field".localized + case .holders: return "coin_analytics.holders_rank.sorting_field".localized + case .fee: return "coin_analytics.project_fee_rank.sorting_field".localized + case .revenue: return "coin_analytics.project_revenue_rank.sorting_field".localized + } } } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankHeaderView.swift deleted file mode 100644 index dbc358fb33..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankHeaderView.swift +++ /dev/null @@ -1,76 +0,0 @@ -import ComponentKit -import RxCocoa -import RxSwift -import SnapKit -import ThemeKit -import UIExtensions -import UIKit - -class CoinRankHeaderView: UITableViewHeaderFooterView { - static let height: CGFloat = .heightSingleLineCell - - private let viewModel: CoinRankViewModel - private let disposeBag = DisposeBag() - - private let sortButton = SecondaryCircleButton() - - init(viewModel: CoinRankViewModel) { - self.viewModel = viewModel - - super.init(reuseIdentifier: nil) - - backgroundView = UIView() - backgroundView?.backgroundColor = .themeNavigationBarBackground - - let separatorView = UIView() - - contentView.addSubview(separatorView) - separatorView.snp.makeConstraints { maker in - maker.leading.top.trailing.equalToSuperview() - maker.height.equalTo(CGFloat.heightOnePixel) - } - - separatorView.backgroundColor = .themeSteel20 - - contentView.addSubview(sortButton) - sortButton.snp.makeConstraints { maker in - maker.leading.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - } - - sortButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - sortButton.addTarget(self, action: #selector(onTapSortButton), for: .touchUpInside) - - if let selectorItems = viewModel.selectorItems { - let selector = SelectorButton() - - contentView.addSubview(selector) - selector.snp.makeConstraints { maker in - maker.trailing.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - maker.height.equalTo(28) - } - - selector.set(items: selectorItems) - selector.setSelected(index: viewModel.selectorIndex) - selector.onSelect = { [weak self] index in - self?.viewModel.onSelectSelector(index: index) - } - } - - subscribe(disposeBag, viewModel.sortDirectionDriver) { [weak self] in self?.syncSortButton(ascending: $0) } - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc private func onTapSortButton() { - viewModel.onToggleSortDirection() - } - - private func syncSortButton(ascending: Bool) { - sortButton.set(image: UIImage(named: ascending ? "sort_l2h_20" : "sort_h2l_20")) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankModule.swift deleted file mode 100644 index 287827273e..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankModule.swift +++ /dev/null @@ -1,36 +0,0 @@ -import SwiftUI -import ThemeKit -import UIKit - -enum CoinRankModule { - static func viewController(type: RankType) -> UIViewController { - let service = CoinRankService( - type: type, - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager - ) - - let viewModel = CoinRankViewModel(service: service) - let viewController = CoinRankViewController(viewModel: viewModel) - - return ThemeNavigationController(rootViewController: viewController) - } - - static func newView(type: RankType) -> UIViewController { - let isPresented = Binding(get: { true }, set: { _ in }) - return RankView(isPresented: isPresented, type: type).toViewController() - } -} - -extension CoinRankModule { - enum RankType { - case cexVolume - case dexVolume - case dexLiquidity - case address - case txCount - case holders - case fee - case revenue - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankService.swift deleted file mode 100644 index 6ed426b1f2..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankService.swift +++ /dev/null @@ -1,161 +0,0 @@ -import Foundation -import HsExtensions -import MarketKit - -class CoinRankService { - let type: CoinRankModule.RankType - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private var tasks = Set() - - @PostPublished private(set) var state: State = .loading - - var sortDirectionAscending: Bool = false { - didSet { - syncIfPossible(reorder: true) - } - } - - var timePeriod: HsTimePeriod = .month1 { - didSet { - syncIfPossible(reorder: true) - } - } - - private var internalItems: [InternalItem]? - - init(type: CoinRankModule.RankType, marketKit: MarketKit.Kit, currencyManager: CurrencyManager) { - self.type = type - self.marketKit = marketKit - self.currencyManager = currencyManager - - sync() - } - - func sync() { - tasks = Set() - - state = .loading - - Task { [weak self, marketKit, currencyManager, type] in - do { - let currencyCode = currencyManager.baseCurrency.code - let values: [Value] - - switch type { - case .cexVolume: values = try await marketKit.cexVolumeRanks(currencyCode: currencyCode).map { .multi(value: $0) } - case .dexVolume: values = try await marketKit.dexVolumeRanks(currencyCode: currencyCode).map { .multi(value: $0) } - case .dexLiquidity: values = try await marketKit.dexLiquidityRanks().map { .single(value: $0) } - case .address: values = try await marketKit.activeAddressRanks().map { .multi(value: $0) } - case .txCount: values = try await marketKit.transactionCountRanks().map { .multi(value: $0) } - case .holders: values = try await marketKit.holdersRanks().map { .single(value: $0) } - case .fee: values = try await marketKit.feeRanks(currencyCode: currencyCode).map { .multi(value: $0) } - case .revenue: values = try await marketKit.revenueRanks(currencyCode: currencyCode).map { .multi(value: $0) } - } - - self?.handle(values: values) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } - - private func handle(values: [Value]) { - do { - let coins = try marketKit.allCoins() - - var coinMap = [String: Coin]() - coins.forEach { coinMap[$0.uid] = $0 } - - internalItems = values.compactMap { value in - guard let coin = coinMap[value.coinUid] else { - return nil - } - - return InternalItem(coin: coin, value: value) - } - - syncIfPossible(reorder: false) - } catch { - state = .failed(error: error) - } - } - - private func syncIfPossible(reorder: Bool) { - guard let internalItems else { - return - } - - let items = internalItems.compactMap { internalItem -> Item? in - let resolvedValue: Decimal? - - switch internalItem.value { - case let .multi(value): - switch timePeriod { - case .day1: resolvedValue = value.value1d - case .week1: resolvedValue = value.value7d - default: resolvedValue = value.value30d - } - case let .single(value): - resolvedValue = value.value - } - - guard let resolvedValue else { - return nil - } - - return Item(coin: internalItem.coin, value: resolvedValue) - } - - let filteredItems = items.sorted { $0.value > $1.value }.prefix(300) - let indexedItems = filteredItems.enumerated().map { index, item in - IndexedItem(index: index + 1, coin: item.coin, value: item.value) - } - - let sortedIndexedItems = sortDirectionAscending ? indexedItems.sorted { $0.value < $1.value } : indexedItems - - state = .loaded(items: sortedIndexedItems, reorder: reorder) - } -} - -extension CoinRankService { - var currency: Currency { - currencyManager.baseCurrency - } -} - -extension CoinRankService { - private struct InternalItem { - let coin: Coin - let value: Value - } - - private enum Value { - case multi(value: RankMultiValue) - case single(value: RankValue) - - var coinUid: String { - switch self { - case let .multi(value): return value.uid - case let .single(value): return value.uid - } - } - } - - enum State { - case loading - case loaded(items: [IndexedItem], reorder: Bool) - case failed(error: Error) - } - - private struct Item { - let coin: Coin - let value: Decimal - } - - struct IndexedItem { - let index: Int - let coin: Coin - let value: Decimal - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewController.swift deleted file mode 100644 index e318e7029b..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewController.swift +++ /dev/null @@ -1,171 +0,0 @@ -import ComponentKit -import HUD -import RxSwift -import SectionsTableView -import ThemeKit -import UIKit - -class CoinRankViewController: ThemeViewController { - private let viewModel: CoinRankViewModel - private let headerView: CoinRankHeaderView - private let disposeBag = DisposeBag() - - private let tableView = SectionsTableView(style: .plain) - private let spinner = HUDActivityView.create(with: .medium24) - private let errorView = PlaceholderViewModule.reachabilityView() - - private var viewItems: [CoinRankViewModel.ViewItem]? - - init(viewModel: CoinRankViewModel) { - self.viewModel = viewModel - headerView = CoinRankHeaderView(viewModel: viewModel) - - super.init() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - view.addSubview(tableView) - tableView.snp.makeConstraints { maker in - maker.edges.equalToSuperview() - } - - tableView.sectionHeaderTopPadding = 0 - tableView.separatorStyle = .none - tableView.backgroundColor = .clear - tableView.sectionDataSource = self - - tableView.registerCell(forClass: MarketHeaderCell.self) - - view.addSubview(spinner) - spinner.snp.makeConstraints { maker in - maker.center.equalTo(view.safeAreaLayoutGuide) - } - - spinner.startAnimating() - - view.addSubview(errorView) - errorView.snp.makeConstraints { maker in - maker.edges.equalTo(view.safeAreaLayoutGuide) - } - - errorView.configureSyncError(action: { [weak self] in self?.viewModel.onTapRetry() }) - - 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 - } - subscribe(disposeBag, viewModel.scrollToTopSignal) { [weak self] in self?.scrollToTop() } - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - private func sync(viewItems: [CoinRankViewModel.ViewItem]?) { - self.viewItems = viewItems - - tableView.isHidden = viewItems == nil - tableView.reload() - } - - private func scrollToTop() { - tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .bottom, animated: true) - } -} - -extension CoinRankViewController: SectionsDataSource { - private func row(viewItem: CoinRankViewModel.ViewItem, index: Int, isLast: Bool) -> RowProtocol { - let statPage = viewModel.statPage - - return CellBuilderNew.row( - rootElement: .hStack([ - .text { component in - component.font = .captionSB - component.textColor = .themeGray - component.text = viewItem.rank - component.textAlignment = .center - - component.snp.remakeConstraints { maker in - maker.width.equalTo(40) - } - }, - .margin8, - .image32 { component in - component.setImage(urlString: viewItem.imageUrl, placeholder: UIImage(named: "placeholder_circle_32")) - }, - .vStackCentered([ - .textElement(text: .body(viewItem.code)), - .margin(1), - .textElement(text: .subhead2(viewItem.name)), - ]), - .textElement(text: .body(viewItem.value), parameters: .rightAlignment), - ]), - layoutMargins: UIEdgeInsets(top: 0, left: .margin8, bottom: 0, right: CellBuilderNew.defaultMargin), - tableView: tableView, - id: "row-\(index)", - height: .heightDoubleLineCell, - autoDeselect: true, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - }, - action: { [weak self] in - let coinUid = viewItem.uid - - if let viewController = CoinPageModule.viewController(coinUid: coinUid) { - self?.present(viewController, animated: true) - stat(page: statPage, event: .openCoin(coinUid: coinUid)) - } - } - ) - } - - private func bind(cell: MarketHeaderCell) { - cell.set( - title: viewModel.title, - description: viewModel.description, - imageMode: .remote(imageUrl: viewModel.imageUid.headerImageUrl) - ) - } - - func buildSections() -> [SectionProtocol] { - guard let viewItems else { - return [] - } - - return [ - Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { [weak self] cell, _ in - self?.bind(cell: cell) - } - ), - ] - ), - Section( - id: "coins", - headerState: .static(view: headerView, height: CoinRankHeaderView.height), - footerState: .marginColor(height: .margin32, color: .clear), - rows: viewItems.enumerated().map { index, viewItem in - row(viewItem: viewItem, index: index, isLast: index == viewItems.count - 1) - } - ), - ] - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewModel.swift deleted file mode 100644 index 241fe6f403..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Coin/Ranks/CoinRankViewModel.swift +++ /dev/null @@ -1,187 +0,0 @@ -import Combine -import Foundation -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -class CoinRankViewModel { - private let timePeriods: [HsTimePeriod] = [.day1, .week1, .month1] - - private let service: CoinRankService - private var cancellables = Set() - - private let viewItemsRelay = BehaviorRelay<[ViewItem]?>(value: nil) - private let loadingRelay = BehaviorRelay(value: false) - private let syncErrorRelay = BehaviorRelay(value: false) - private let sortDirectionRelay: BehaviorRelay - 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) - - sync(state: service.state) - } - - private func sync(state: CoinRankService.State) { - switch state { - case .loading: - viewItemsRelay.accept(nil) - loadingRelay.accept(true) - syncErrorRelay.accept(false) - case let .loaded(items, reorder): - viewItemsRelay.accept(viewItems(items: items)) - loadingRelay.accept(false) - syncErrorRelay.accept(false) - - if reorder { - scrollToTopRelay.accept(()) - } - case .failed: - viewItemsRelay.accept(nil) - loadingRelay.accept(false) - syncErrorRelay.accept(true) - } - } - - private func viewItems(items: [CoinRankService.IndexedItem]) -> [ViewItem] { - let currency = service.currency - return items.enumerated().map { index, item in - viewItem(index: index, item: item, currency: currency) - } - } - - 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) - ) - } - - private func formatted(value: Decimal, currency: Currency) -> String? { - switch service.type { - case .cexVolume, .dexVolume, .dexLiquidity, .fee, .revenue: - return ValueFormatter.instance.formatShort(currencyValue: CurrencyValue(currency: currency, value: value)) - case .address, .txCount, .holders: - return ValueFormatter.instance.formatShort(value: value) - } - } -} - -extension CoinRankViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { - viewItemsRelay.asDriver() - } - - var loadingDriver: Driver { - loadingRelay.asDriver() - } - - var syncErrorDriver: Driver { - syncErrorRelay.asDriver() - } - - var scrollToTopSignal: Signal { - scrollToTopRelay.asSignal() - } - - var title: String { - switch service.type { - case .cexVolume: return "coin_analytics.cex_volume_rank".localized - case .dexVolume: return "coin_analytics.dex_volume_rank".localized - case .dexLiquidity: return "coin_analytics.dex_liquidity_rank".localized - case .address: return "coin_analytics.active_addresses_rank".localized - case .txCount: return "coin_analytics.transaction_count_rank".localized - case .holders: return "coin_analytics.holders_rank".localized - case .fee: return "coin_analytics.project_fee_rank".localized - case .revenue: return "coin_analytics.project_revenue_rank".localized - } - } - - var description: String { - switch service.type { - case .cexVolume: return "coin_analytics.cex_volume_rank.description".localized - case .dexVolume: return "coin_analytics.dex_volume_rank.description".localized - case .dexLiquidity: return "coin_analytics.dex_liquidity_rank.description".localized - case .address: return "coin_analytics.active_addresses_rank.description".localized - case .txCount: return "coin_analytics.transaction_count_rank.description".localized - case .holders: return "coin_analytics.holders_rank.description".localized - case .fee: return "coin_analytics.project_fee_rank.description".localized - case .revenue: return "coin_analytics.project_revenue_rank.description".localized - } - } - - var imageUid: String { - switch service.type { - case .cexVolume: return "cex_volume" - case .dexVolume: return "dex_volume" - case .dexLiquidity: return "dex_liquidity" - case .address: return "active_addresses" - case .txCount: return "trx_count" - case .holders: return "holders" - case .fee: return "fee" - case .revenue: return "revenue" - } - } - - var sortDirectionDriver: Driver { - sortDirectionRelay.asDriver() - } - - var statPage: StatPage { - switch service.type { - case .cexVolume: return .coinRankCexVolume - case .dexVolume: return .coinRankDexVolume - case .dexLiquidity: return .coinRankDexLiquidity - case .address: return .coinRankAddress - case .txCount: return .coinRankTxCount - case .holders: return .coinRankHolders - case .fee: return .coinRankFee - case .revenue: return .coinRankRevenue - } - } - - func onToggleSortDirection() { - service.sortDirectionAscending = !service.sortDirectionAscending - sortDirectionRelay.accept(service.sortDirectionAscending) - } - - var selectorItems: [String]? { - switch service.type { - case .cexVolume, .dexVolume, .address, .txCount, .fee, .revenue: return timePeriods.map(\.shortTitle) - case .dexLiquidity, .holders: return nil - } - } - - var selectorIndex: Int { - timePeriods.firstIndex(of: service.timePeriod) ?? 0 - } - - func onSelectSelector(index: Int) { - service.timePeriod = timePeriods[index] - } - - func onTapRetry() { - service.sync() - } -} - -extension CoinRankViewModel { - struct ViewItem { - let uid: String - let rank: String - let imageUrl: String - let code: String - let name: String - let value: String? - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift index dd297080af..faaff8d6c6 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Main/MainViewController.swift @@ -84,18 +84,11 @@ class MainViewController: ThemeTabBarController { private func sync(balanceTabState _: MainViewModel.BalanceTabState) { var viewControllers = [UIViewController]() if viewModel.showMarket { - if App.shared.localStorage.newMarketTabEnabled { - let marketModule = marketModule ?? MarketView().toNavigationViewController() - marketModule.tabBarItem = UITabBarItem(title: "market.tab_bar_item".localized, image: UIImage(named: "market_2_24"), tag: 0) - self.marketModule = marketModule + let marketModule = marketModule ?? MarketView().toNavigationViewController() + marketModule.tabBarItem = UITabBarItem(title: "market.tab_bar_item".localized, image: UIImage(named: "market_2_24"), tag: 0) + self.marketModule = marketModule - viewControllers.append(marketModule) - } else { - let marketModule = marketModule ?? ThemeNavigationController(rootViewController: MarketModule.viewController()) - self.marketModule = marketModule - - viewControllers.append(marketModule) - } + viewControllers.append(marketModule) } else { marketModule = nil } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/Etf/MarketEtfFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/MarketEtfFetcher.swift similarity index 100% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/Etf/MarketEtfFetcher.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/MarketEtfFetcher.swift diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/MarketGlobalFetcher.swift similarity index 100% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalFetcher.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/MarketGlobalFetcher.swift diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/MarketGlobalModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/MarketGlobalModule.swift new file mode 100644 index 0000000000..e2c4d2a875 --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/MarketGlobalModule.swift @@ -0,0 +1,13 @@ +enum MarketGlobalModule { + static let dominance = "dominance" + static let totalAssets = "total_assets" + static let totalInflow = "total_inflow" + + enum MetricsType: Identifiable { + case totalMarketCap, volume24h, defiCap, tvlInDefi + + var id: Self { + self + } + } +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformMarketCapFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/TopPlatformMarketCapFetcher.swift similarity index 100% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformMarketCapFetcher.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Fetchers/TopPlatformMarketCapFetcher.swift diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/FilteredList/MarketFilteredListService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/FilteredList/MarketFilteredListService.swift deleted file mode 100644 index 7a65ad11ba..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/FilteredList/MarketFilteredListService.swift +++ /dev/null @@ -1,103 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -protocol IMarketFilteredListProvider { - func marketInfos(currencyCode: String) async throws -> [MarketInfo] -} - -class MarketFilteredListService: IMarketMultiSortHeaderService { - private let currencyManager: CurrencyManager - private let provider: IMarketFilteredListProvider - private let statPage: StatPage - private var tasks = Set() - - @PostPublished private(set) var state: MarketListServiceState = .loading - - var sortingField: MarketModule.SortingField = .highestCap { - didSet { - syncIfPossible() - - stat(page: statPage, event: .switchSortType(sortType: sortingField.statSortType)) - } - } - - init(currencyManager: CurrencyManager, provider: IMarketFilteredListProvider, statPage: StatPage) { - self.currencyManager = currencyManager - self.provider = provider - self.statPage = statPage - - syncMarketInfos() - } - - private func syncMarketInfos() { - tasks = Set() - - if case .failed = state { - state = .loading - } - - Task { [weak self, provider, currency] in - do { - let marketInfos = try await provider.marketInfos(currencyCode: currency.code) - self?.sync(marketInfos: marketInfos) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } - - private func sync(marketInfos: [MarketInfo], reorder: Bool = false) { - state = .loaded(items: marketInfos.sorted(sortingField: sortingField, priceChangeType: priceChangeType), softUpdate: false, reorder: reorder) - } - - private func syncIfPossible() { - guard case let .loaded(marketInfos, _, _) = state else { - return - } - - sync(marketInfos: marketInfos, reorder: true) - } -} - -extension MarketFilteredListService: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func refresh() { - syncMarketInfos() - } -} - -extension MarketFilteredListService: IMarketListCoinUidService { - func coinUid(index: Int) -> String? { - guard case let .loaded(marketInfos, _, _) = state, index < marketInfos.count else { - return nil - } - - return marketInfos[index].fullCoin.coin.uid - } -} - -extension MarketFilteredListService: IMarketListDecoratorService { - var initialIndex: Int { - 0 - } - - var currency: Currency { - currencyManager.baseCurrency - } - - var priceChangeType: MarketModule.PriceChangeType { - .day - } - - func onUpdate(index _: Int) { - if case let .loaded(marketInfos, _, _) = state { - state = .loaded(items: marketInfos, softUpdate: false, reorder: false) - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Global/MarketGlobalView.swift similarity index 98% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalView.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Global/MarketGlobalView.swift index a6161d80d7..a68cd0a4cd 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Global/MarketGlobalView.swift @@ -34,7 +34,7 @@ struct MarketGlobalView: View { } .animation(.default, value: viewModel.marketGlobal == nil) .sheet(isPresented: $tvlPresented) { - MarketTvlView(isPresented: $tvlPresented) + ThemeNavigationView { MarketTvlView() } .onFirstAppear { stat(page: .markets, event: .open(page: .globalMetricsTvlInDefi)) } } .sheet(isPresented: $marketCapPresented) { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Global/MarketGlobalViewModel.swift similarity index 100% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalViewModel.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Global/MarketGlobalViewModel.swift diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryMarketCapFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryMarketCapFetcher.swift deleted file mode 100644 index e32221d729..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryMarketCapFetcher.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Chart -import Foundation -import MarketKit - -class MarketCategoryMarketCapFetcher { - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private let category: String - - init(currencyManager: CurrencyManager, marketKit: MarketKit.Kit, category: String) { - self.marketKit = marketKit - self.currencyManager = currencyManager - self.category = category - } -} - -extension MarketCategoryMarketCapFetcher: IMetricChartFetcher { - var valueType: MetricChartModule.ValueType { - .compactCurrencyValue(currencyManager.baseCurrency) - } - - var intervals: [HsPeriodType] { - [HsTimePeriod.day1, .week1, .month1].periodTypes - } - - func fetch(interval: HsPeriodType) async throws -> MetricChartModule.ItemData { - guard case let .byPeriod(interval) = interval else { - throw MetricChartModule.FetchError.onlyHsTimePeriod - } - - let points = try await marketKit.coinCategoryMarketCapChart(category: category, currencyCode: currencyManager.baseCurrency.code, timePeriod: interval) - - let items = points.map { point -> MetricChartModule.Item in - MetricChartModule.Item(value: point.marketCap, timestamp: point.timestamp) - } - - return MetricChartModule.ItemData(items: items, type: .regular) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryModule.swift deleted file mode 100644 index afc4ab7413..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryModule.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Chart -import MarketKit -import ThemeKit -import UIKit - -enum MarketCategoryModule { - static func viewController(category: CoinCategory) -> UIViewController { - let service = MarketCategoryService( - category: category, - marketKit: App.shared.marketKit, - languageManager: LanguageManager.shared - ) - - let listService = MarketFilteredListService(currencyManager: App.shared.currencyManager, provider: service, statPage: .coinCategory) - let watchlistToggleService = MarketWatchlistToggleService(coinUidService: listService, watchlistManager: App.shared.watchlistManager, statPage: .coinCategory) - - let marketCapFetcher = MarketCategoryMarketCapFetcher(currencyManager: App.shared.currencyManager, marketKit: App.shared.marketKit, category: category.uid) - let chartService = MetricChartService(chartFetcher: marketCapFetcher, interval: .byPeriod(.day1), statPage: .coinCategory) - let factory = MetricChartFactory(currentLocale: LanguageManager.shared.currentLocale) - let chartViewModel = MetricChartViewModel(service: chartService, factory: factory) - - let decorator = MarketListMarketFieldDecorator(service: listService, statPage: .coinCategory) - let viewModel = MarketCategoryViewModel(service: service) - let listViewModel = MarketListWatchViewModel(service: listService, watchlistToggleService: watchlistToggleService, decorator: decorator) - let headerViewModel = MarketMultiSortHeaderViewModel(service: listService, decorator: decorator) - - let viewController = MarketCategoryViewController(viewModel: viewModel, chartViewModel: chartViewModel, listViewModel: listViewModel, headerViewModel: headerViewModel) - - return ThemeNavigationController(rootViewController: viewController) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryService.swift deleted file mode 100644 index c327b9620a..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryService.swift +++ /dev/null @@ -1,25 +0,0 @@ -import MarketKit - -class MarketCategoryService { - let category: CoinCategory - private let marketKit: MarketKit.Kit - private let languageManager: LanguageManager - - init(category: CoinCategory, marketKit: MarketKit.Kit, languageManager: LanguageManager) { - self.category = category - self.marketKit = marketKit - self.languageManager = languageManager - } -} - -extension MarketCategoryService { - var currentLanguage: String { - languageManager.currentLanguage - } -} - -extension MarketCategoryService: IMarketFilteredListProvider { - func marketInfos(currencyCode: String) async throws -> [MarketInfo] { - try await marketKit.marketInfos(categoryUid: category.uid, currencyCode: currencyCode) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewController.swift deleted file mode 100644 index 1187cd1670..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewController.swift +++ /dev/null @@ -1,86 +0,0 @@ -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketCategoryViewController: MarketListViewController { - private let viewModel: MarketCategoryViewModel - private let multiSortHeaderView: MarketMultiSortHeaderView - - override var viewController: UIViewController? { self } - override var headerView: UITableViewHeaderFooterView? { multiSortHeaderView } - override var refreshEnabled: Bool { false } - - private let chartViewModel: MetricChartViewModel - - /* Chart section */ - private let chartCell: ChartCell - private let chartRow: StaticRow - - init(viewModel: MarketCategoryViewModel, chartViewModel: MetricChartViewModel, listViewModel: IMarketListViewModel, headerViewModel: MarketMultiSortHeaderViewModel) { - self.viewModel = viewModel - self.chartViewModel = chartViewModel - multiSortHeaderView = MarketMultiSortHeaderView(viewModel: headerViewModel) - - chartCell = ChartCell(viewModel: chartViewModel, configuration: .baseChart) - chartRow = StaticRow( - cell: chartCell, - id: "chartView", - height: chartCell.cellHeight - ) - - super.init(listViewModel: listViewModel, statPage: .coinCategory) - - multiSortHeaderView.viewController = self - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: MarketHeaderCell.self) - - chartRow.onReady = { [weak chartCell] in chartCell?.onLoad() } - chartViewModel.start() - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded: Bool) -> [SectionProtocol] { - var sections = [Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { [weak self] cell, _ in - self?.bind(cell: cell) - } - ), - ] - )] - - if loaded { - sections.append(Section(id: "chart", rows: [chartRow])) - } - - return sections - } - - private func bind(cell: MarketHeaderCell) { - cell.set( - title: viewModel.title, - description: viewModel.description, - imageMode: .remote(imageUrl: viewModel.imageUrl) - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewModel.swift deleted file mode 100644 index efd7bf43f7..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketCategory/MarketCategoryViewModel.swift +++ /dev/null @@ -1,21 +0,0 @@ -class MarketCategoryViewModel { - private let service: MarketCategoryService - - init(service: MarketCategoryService) { - self.service = service - } -} - -extension MarketCategoryViewModel { - var title: String { - service.category.name - } - - var description: String? { - service.category.descriptions[service.currentLanguage] ?? service.category.descriptions.first?.value - } - - var imageUrl: String { - service.category.imageUrl - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalModule.swift deleted file mode 100644 index 3244f5d978..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobal/MarketGlobalModule.swift +++ /dev/null @@ -1,53 +0,0 @@ -import Chart -import RxSwift -import UIKit - -enum MarketGlobalModule { - static let dominance = "dominance" - static let totalAssets = "total_assets" - static let totalInflow = "total_inflow" - - enum MetricsType: Identifiable { - case totalMarketCap, volume24h, defiCap, tvlInDefi - - var id: Self { - self - } - - var title: String { - switch self { - case .totalMarketCap: return "market.global.total_market_cap.title".localized - case .volume24h: return "market.global.volume_24h.title".localized - case .defiCap: return "market.global.defi_cap.title".localized - case .tvlInDefi: return "market.global.tvl_in_defi.title".localized - } - } - - var description: String { - switch self { - case .totalMarketCap: return "market.global.total_market_cap.description".localized - case .volume24h: return "market.global.volume_24h.description".localized - case .defiCap: return "market.global.defi_cap.description".localized - case .tvlInDefi: return "market.global.tvl_in_defi.description".localized - } - } - - var imageUid: String { - switch self { - case .totalMarketCap: return "total_mcap" - case .volume24h: return "total_volume" - case .defiCap: return "defi_cap" - case .tvlInDefi: return "tvl" - } - } - - var marketField: MarketModule.MarketField { - switch self { - case .totalMarketCap: return .marketCap - case .volume24h: return .volume - case .defiCap: return .marketCap - case .tvlInDefi: return .price - } - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketGlobalDefiMetricService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketGlobalDefiMetricService.swift deleted file mode 100644 index 2b64c74670..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketGlobalDefiMetricService.swift +++ /dev/null @@ -1,120 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class MarketGlobalDefiMetricService: IMarketSingleSortHeaderService { - typealias Item = DefiItem - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private let disposeBag = DisposeBag() - private var tasks = Set() - - @PostPublished private(set) var state: MarketListServiceState = .loading - - var sortDirectionAscending: Bool = false { - didSet { - syncIfPossible() - - stat(page: .globalMetricsDefiCap, event: .toggleSortDirection) - } - } - - let initialIndex: Int = 1 - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager) { - self.marketKit = marketKit - self.currencyManager = currencyManager - - syncMarketInfos() - } - - private func syncMarketInfos() { - tasks = Set() - - if case .failed = state { - state = .loading - } - - Task { [weak self, marketKit, currency] in - do { - let marketInfos = try await marketKit.marketInfos(top: MarketModule.MarketTop.top100.rawValue, currencyCode: currency.code, defi: true) - - let rankedItems = marketInfos.enumerated().map { index, info in - Item(marketInfo: info, tvlRank: index + 1) - } - - self?.sync(items: rankedItems) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } - - private func sync(items: [Item], reorder: Bool = false) { - state = .loaded(items: sorted(items: items), softUpdate: false, reorder: reorder) - } - - private func syncIfPossible() { - guard case let .loaded(items, _, _) = state else { - return - } - - sync(items: items, reorder: true) - } - - func sorted(items: [Item]) -> [Item] { - items.sorted { lhsItem, rhsItem in - if sortDirectionAscending { - return lhsItem.tvlRank > rhsItem.tvlRank - } else { - return lhsItem.tvlRank < rhsItem.tvlRank - } - } - } -} - -extension MarketGlobalDefiMetricService: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func refresh() { - syncMarketInfos() - } -} - -extension MarketGlobalDefiMetricService: IMarketListCoinUidService { - func coinUid(index: Int) -> String? { - guard case let .loaded(items, _, _) = state, index < items.count else { - return nil - } - - return items[index].marketInfo.fullCoin.coin.uid - } -} - -extension MarketGlobalDefiMetricService: IMarketListDecoratorService { - var currency: Currency { - currencyManager.baseCurrency - } - - var priceChangeType: MarketModule.PriceChangeType { - .day - } - - func onUpdate(index _: Int) { - if case let .loaded(items, _, _) = state { - state = .loaded(items: items, softUpdate: false, reorder: false) - } - } -} - -extension MarketGlobalDefiMetricService { - struct DefiItem { - let marketInfo: MarketInfo - let tvlRank: Int - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketListDefiDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketListDefiDecorator.swift deleted file mode 100644 index 617af21495..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/DefiCap/MarketListDefiDecorator.swift +++ /dev/null @@ -1,64 +0,0 @@ -import MarketKit - -class MarketListDefiDecorator { - typealias Item = MarketGlobalDefiMetricService.DefiItem - - private let service: IMarketListDecoratorService - - var marketField: MarketModule.MarketField { - didSet { - service.onUpdate(index: marketField.rawValue) - - stat(page: .globalMetricsDefiCap, event: .switchField(field: marketField.statField)) - } - } - - init(service: IMarketListDecoratorService) { - self.service = service - marketField = MarketModule.MarketField.allCases[service.initialIndex] - } -} - -extension MarketListDefiDecorator: IMarketSingleSortHeaderDecorator { - var allFields: [String] { - MarketModule.MarketField.allCases.map(\.title) - } - - var currentFieldIndex: Int { - MarketModule.MarketField.allCases.firstIndex(of: marketField) ?? 0 - } - - 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 - - let price = marketInfo.price.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized - - let dataValue: MarketModule.MarketDataValue - - switch marketField { - case .price: dataValue = .diff(marketInfo.priceChangeValue(type: service.priceChangeType)) - case .volume: dataValue = .volume(marketInfo.totalVolume.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized) - case .marketCap: dataValue = .marketCap(marketInfo.marketCap.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized) - } - - 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 - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricModule.swift deleted file mode 100644 index c4de7a6349..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricModule.swift +++ /dev/null @@ -1,106 +0,0 @@ -import Chart -import ThemeKit -import UIKit - -enum MarketGlobalMetricModule { - static func viewController(type: MarketGlobalModule.MetricsType) -> UIViewController { - let viewController: UIViewController - - switch type { - case .totalMarketCap, .volume24h: viewController = globalMetricViewController(type: type) - case .defiCap: viewController = defiCapViewController() - case .tvlInDefi: viewController = tvlInDefiViewController() - } - - return ThemeNavigationController(rootViewController: viewController) - } - - private static func globalMetricViewController(type: MarketGlobalModule.MetricsType) -> UIViewController { - let service = MarketGlobalMetricService( - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - metricsType: type - ) - - let watchlistToggleService = MarketWatchlistToggleService( - coinUidService: service, - watchlistManager: App.shared.watchlistManager, - statPage: type.statPage - ) - - let decorator = MarketListMarketFieldDecorator(service: service, statPage: type.statPage) - let listViewModel = MarketListWatchViewModel(service: service, watchlistToggleService: watchlistToggleService, decorator: decorator) - let headerViewModel = MarketSingleSortHeaderViewModel(service: service, decorator: decorator) - - let chartFetcher = MarketGlobalFetcher(currencyManager: App.shared.currencyManager, marketKit: App.shared.marketKit, metricsType: type) - let chartService = MetricChartService( - chartFetcher: chartFetcher, - interval: .byPeriod(.day1), - statPage: type.statPage - ) - - let factory = MetricChartFactory(currentLocale: LanguageManager.shared.currentLocale) - let chartViewModel = MetricChartViewModel(service: chartService, factory: factory) - - return MarketGlobalMetricViewController(listViewModel: listViewModel, headerViewModel: headerViewModel, chartViewModel: chartViewModel, metricsType: type) - } - - private static func defiCapViewController() -> UIViewController { - let service = MarketGlobalDefiMetricService( - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager - ) - - let watchlistToggleService = MarketWatchlistToggleService( - coinUidService: service, - watchlistManager: App.shared.watchlistManager, - statPage: .globalMetricsDefiCap - ) - - let decorator = MarketListDefiDecorator(service: service) - let listViewModel = MarketListWatchViewModel(service: service, watchlistToggleService: watchlistToggleService, decorator: decorator) - let headerViewModel = MarketSingleSortHeaderViewModel(service: service, decorator: decorator) - - let chartFetcher = MarketGlobalFetcher(currencyManager: App.shared.currencyManager, marketKit: App.shared.marketKit, metricsType: .defiCap) - let chartService = MetricChartService( - chartFetcher: chartFetcher, - interval: .byPeriod(.day1), - statPage: .globalMetricsDefiCap - ) - - let factory = MetricChartFactory(currentLocale: LanguageManager.shared.currentLocale) - let chartViewModel = MetricChartViewModel(service: chartService, factory: factory) - - return MarketGlobalMetricViewController(listViewModel: listViewModel, headerViewModel: headerViewModel, chartViewModel: chartViewModel, metricsType: MarketGlobalModule.MetricsType.defiCap) - } - - static func tvlInDefiViewController() -> UIViewController { - let service = MarketGlobalTvlMetricService( - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager - ) - - let watchlistToggleService = MarketWatchlistToggleService( - coinUidService: service, - watchlistManager: App.shared.watchlistManager, - statPage: .globalMetricsTvlInDefi - ) - - let decorator = MarketListTvlDecorator(service: service) - let listViewModel = MarketListWatchViewModel(service: service, watchlistToggleService: watchlistToggleService, decorator: decorator) - let headerViewModel = MarketTvlSortHeaderViewModel(service: service, decorator: decorator) - - let chartFetcher = MarketGlobalTvlFetcher(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, marketGlobalTvlPlatformService: service) - let chartService = MetricChartService( - chartFetcher: chartFetcher, - interval: .byPeriod(.day1), - statPage: .globalMetricsTvlInDefi - ) - service.chartService = chartService - - let factory = MetricChartFactory(currentLocale: LanguageManager.shared.currentLocale) - let chartViewModel = MetricChartViewModel(service: chartService, factory: factory) - - return MarketGlobalTvlMetricViewController(listViewModel: listViewModel, headerViewModel: headerViewModel, chartViewModel: chartViewModel) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricService.swift deleted file mode 100644 index 4faf88f3be..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricService.swift +++ /dev/null @@ -1,109 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class MarketGlobalMetricService: IMarketSingleSortHeaderService { - typealias Item = MarketInfo - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private let disposeBag = DisposeBag() - private var tasks = Set() - - @PostPublished private(set) var state: MarketListServiceState = .loading - - var sortDirectionAscending: Bool = false { - didSet { - syncIfPossible() - - stat(page: metricsType.statPage, event: .toggleSortDirection) - } - } - - private let metricsType: MarketGlobalModule.MetricsType - - let initialIndex: Int - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, metricsType: MarketGlobalModule.MetricsType) { - self.marketKit = marketKit - self.currencyManager = currencyManager - self.metricsType = metricsType - initialIndex = metricsType.marketField.rawValue - - syncMarketInfos() - } - - private func syncMarketInfos() { - tasks = Set() - - if case .failed = state { - state = .loading - } - - Task { [weak self, marketKit, currency] in - do { - let marketInfos = try await marketKit.marketInfos(top: MarketModule.MarketTop.top100.rawValue, currencyCode: currency.code) - self?.sync(marketInfos: marketInfos) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } - - private var sortingField: MarketModule.SortingField { - switch metricsType { - case .volume24h: return sortDirectionAscending ? .lowestVolume : .highestVolume - default: return sortDirectionAscending ? .lowestCap : .highestCap - } - } - - private func sync(marketInfos: [MarketInfo], reorder: Bool = false) { - state = .loaded(items: marketInfos.sorted(sortingField: sortingField, priceChangeType: priceChangeType), softUpdate: false, reorder: reorder) - } - - private func syncIfPossible() { - guard case let .loaded(marketInfos, _, _) = state else { - return - } - - sync(marketInfos: marketInfos, reorder: true) - } -} - -extension MarketGlobalMetricService: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func refresh() { - syncMarketInfos() - } -} - -extension MarketGlobalMetricService: IMarketListCoinUidService { - func coinUid(index: Int) -> String? { - guard case let .loaded(marketInfos, _, _) = state, index < marketInfos.count else { - return nil - } - - return marketInfos[index].fullCoin.coin.uid - } -} - -extension MarketGlobalMetricService: IMarketListDecoratorService { - var currency: Currency { - currencyManager.baseCurrency - } - - var priceChangeType: MarketModule.PriceChangeType { - .day - } - - func onUpdate(index _: Int) { - if case let .loaded(marketInfos, _, _) = state { - state = .loaded(items: marketInfos, softUpdate: false, reorder: false) - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricViewController.swift deleted file mode 100644 index 3b2317ae57..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricViewController.swift +++ /dev/null @@ -1,108 +0,0 @@ -import Chart -import ComponentKit -import RxSwift -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketGlobalMetricViewController: MarketListViewController { - private let metricsType: MarketGlobalModule.MetricsType - private let disposeBag = DisposeBag() - private let sortHeaderView: UITableViewHeaderFooterView - - override var headerView: UITableViewHeaderFooterView? { sortHeaderView } - - override var viewController: UIViewController? { self } - override var refreshEnabled: Bool { false } - - private let chartViewModel: MetricChartViewModel - private let chartCell: ChartCell - private let chartRow: StaticRow - - init(listViewModel: IMarketListViewModel, headerViewModel: MarketSingleSortHeaderViewModel, chartViewModel: MetricChartViewModel, metricsType: MarketGlobalModule.MetricsType) { - self.chartViewModel = chartViewModel - self.metricsType = metricsType - sortHeaderView = MarketSingleSortHeaderView(viewModel: headerViewModel) - - let configuration: ChartConfiguration - switch metricsType { - case .totalMarketCap: configuration = .marketCapChart - default: configuration = .baseChart - } - - chartCell = ChartCell(viewModel: chartViewModel, configuration: configuration) - chartRow = StaticRow( - cell: chartCell, - id: "chartView", - height: chartCell.cellHeight - ) - - let statPage: StatPage - - switch metricsType { - case .totalMarketCap: statPage = .globalMetricsMarketCap - case .volume24h: statPage = .globalMetricsVolume - case .defiCap: statPage = .globalMetricsDefiCap - case .tvlInDefi: statPage = .globalMetricsTvlInDefi - } - - super.init(listViewModel: listViewModel, statPage: statPage) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: MarketHeaderCell.self) - - chartRow.onReady = { [weak chartCell] in chartCell?.onLoad() } - - tableView.buildSections() - chartViewModel.start() - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded: Bool) -> [SectionProtocol] { - guard loaded else { - return [] - } - - return [ - Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { [weak self] cell, _ in - self?.bind(cell: cell) - } - ), - ] - ), - Section( - id: "chart", - rows: [chartRow] - ), - ] - } - - private func bind(cell: MarketHeaderCell) { - cell.set( - title: metricsType.title, - description: metricsType.description, - imageMode: .remote(imageUrl: metricsType.imageUid.headerImageUrl) - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricsView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricsView.swift deleted file mode 100644 index 24ad3c6b53..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/MarketGlobalMetricsView.swift +++ /dev/null @@ -1,14 +0,0 @@ -import SwiftUI -import ThemeKit - -struct MarketGlobalMetricsView: UIViewControllerRepresentable { - typealias UIViewControllerType = UIViewController - - let metricsType: MarketGlobalModule.MetricsType - - func makeUIViewController(context _: Context) -> UIViewController { - MarketGlobalMetricModule.viewController(type: metricsType) - } - - func updateUIViewController(_: UIViewController, context _: Context) {} -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlFetcher.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlFetcher.swift deleted file mode 100644 index f10abd77d2..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlFetcher.swift +++ /dev/null @@ -1,42 +0,0 @@ -import Chart -import Combine -import Foundation -import MarketKit - -class MarketGlobalTvlFetcher { - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private let service: MarketGlobalTvlMetricService - - private let needUpdateSubject = PassthroughSubject() - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, marketGlobalTvlPlatformService: MarketGlobalTvlMetricService) { - self.marketKit = marketKit - self.currencyManager = currencyManager - service = marketGlobalTvlPlatformService - } -} - -extension MarketGlobalTvlFetcher: IMetricChartFetcher { - var valueType: MetricChartModule.ValueType { - .compactCurrencyValue(currencyManager.baseCurrency) - } - - var needUpdatePublisher: AnyPublisher { - service.$marketPlatformField.map { _ in () }.eraseToAnyPublisher() - } - - func fetch(interval: HsPeriodType) async throws -> MetricChartModule.ItemData { - guard case let .byPeriod(interval) = interval else { - throw MetricChartModule.FetchError.onlyHsTimePeriod - } - - let points = try await marketKit.marketInfoGlobalTvl(platform: service.marketPlatformField.chain, currencyCode: currencyManager.baseCurrency.code, timePeriod: interval) - - let items = points.map { point -> MetricChartModule.Item in - MetricChartModule.Item(value: point.value, timestamp: point.timestamp) - } - - 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 deleted file mode 100644 index cc8d9bf605..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricService.swift +++ /dev/null @@ -1,178 +0,0 @@ -import Combine -import Foundation -import HsExtensions -import MarketKit - -class MarketGlobalTvlMetricService { - typealias Item = DefiCoin - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - - private var tasks = Set() - private var cancellables = Set() - - weak var chartService: MetricChartService? { - didSet { - subscribeChart() - } - } - - private var internalState: State = .loading { - didSet { - syncState() - } - } - - @PostPublished private(set) var state: MarketListServiceState = .loading - - var sortDirectionAscending: Bool = false { - didSet { - syncIfPossible(reorder: true) - - stat(page: .globalMetricsTvlInDefi, event: .toggleSortDirection) - } - } - - @PostPublished var marketPlatformField: MarketModule.MarketPlatformField = .all { - didSet { - syncIfPossible(reorder: true) - - stat(page: .globalMetricsTvlInDefi, event: .switchTvlChain(chain: marketPlatformField.statTvlChain)) - } - } - - var marketTvlField: MarketModule.MarketTvlField = .diff { - didSet { - syncIfPossible() - - stat(page: .globalMetricsTvlInDefi, event: .toggleTvlField(field: marketTvlField.statField)) - } - } - - private(set) var priceChangePeriod: HsPeriodType = .byPeriod(.day1) { - didSet { - syncIfPossible() - } - } - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager) { - self.marketKit = marketKit - self.currencyManager = currencyManager - - syncDefiCoins() - } - - private func syncDefiCoins() { - tasks = Set() - - if case .failed = state { - internalState = .loading - } - - Task { [weak self, marketKit, currency] in - do { - let defiCoins = try await marketKit.defiCoins(currencyCode: currency.code) - self?.internalState = .loaded(defiCoins: defiCoins) - } catch { - self?.internalState = .failed(error: error) - } - }.store(in: &tasks) - } - - private func syncState(reorder: Bool = false) { - switch internalState { - case .loading: - state = .loading - case let .loaded(defiCoins): - let defiCoins = defiCoins - .filter { defiCoin in - switch marketPlatformField { - case .all: return true - default: return defiCoin.chains.contains(marketPlatformField.chain) - } - } - .sorted { lhsDefiCoin, rhsDefiCoin in - let lhsTvl = lhsDefiCoin.tvl(marketPlatformField: marketPlatformField) ?? 0 - let rhsTvl = rhsDefiCoin.tvl(marketPlatformField: marketPlatformField) ?? 0 - return sortDirectionAscending ? lhsTvl < rhsTvl : lhsTvl > rhsTvl - } - state = .loaded(items: defiCoins, softUpdate: false, reorder: reorder) - case let .failed(error): - state = .failed(error: error) - } - } - - private func syncIfPossible(reorder: Bool = false) { - guard case .loaded = internalState else { - return - } - - syncState(reorder: reorder) - } - - private func subscribeChart() { - cancellables = Set() - - guard let chartService else { - return - } - - chartService.$interval - .sink { [weak self] in self?.priceChangePeriod = $0 } - .store(in: &cancellables) - } -} - -extension MarketGlobalTvlMetricService { - var currency: Currency { - currencyManager.baseCurrency - } -} - -extension MarketGlobalTvlMetricService: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func refresh() { - syncDefiCoins() - } -} - -extension MarketGlobalTvlMetricService: IMarketListCoinUidService { - func coinUid(index: Int) -> String? { - guard case let .loaded(defiCoins, _, _) = state, index < defiCoins.count else { - return nil - } - - switch defiCoins[index].type { - case let .fullCoin(fullCoin): return fullCoin.coin.uid - default: return nil - } - } -} - -extension MarketGlobalTvlMetricService { - private enum State { - case loading - case loaded(defiCoins: [DefiCoin]) - case failed(error: Error) - } -} - -extension DefiCoin { - func tvl(marketPlatformField: MarketModule.MarketPlatformField) -> Decimal? { - switch marketPlatformField { - case .all: return tvl - default: return chainTvls[marketPlatformField.chain] - } - } - - func tvl(platforms: MarketTvlViewModel.Platforms) -> Decimal? { - switch platforms { - case .all: return tvl - default: return chainTvls[platforms.chain] - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricViewController.swift deleted file mode 100644 index fceef3e06c..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketGlobalTvlMetricViewController.swift +++ /dev/null @@ -1,99 +0,0 @@ -import Chart -import ComponentKit -import RxSwift -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketGlobalTvlMetricViewController: MarketListViewController { - private let disposeBag = DisposeBag() - - private let headerViewModel: MarketTvlSortHeaderViewModel - private let sortHeaderView: MarketTvlSortHeaderView - - override var headerView: UITableViewHeaderFooterView? { sortHeaderView } - - override var viewController: UIViewController? { self } - override var refreshEnabled: Bool { false } - - private let chartViewModel: MetricChartViewModel - private let chartCell: ChartCell - private let chartRow: StaticRow - - init(listViewModel: IMarketListViewModel, headerViewModel: MarketTvlSortHeaderViewModel, chartViewModel: MetricChartViewModel) { - self.chartViewModel = chartViewModel - self.headerViewModel = headerViewModel - - sortHeaderView = MarketTvlSortHeaderView(viewModel: headerViewModel) - - chartCell = ChartCell(viewModel: chartViewModel, configuration: .baseChart) - chartRow = StaticRow( - cell: chartCell, - id: "chartView", - height: chartCell.cellHeight - ) - - super.init(listViewModel: listViewModel, statPage: .globalMetricsTvlInDefi) - - sortHeaderView.viewController = self - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: MarketHeaderCell.self) - - chartRow.onReady = { [weak chartCell] in chartCell?.onLoad() } - - tableView.buildSections() - chartViewModel.start() - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded: Bool) -> [SectionProtocol] { - guard loaded else { - return [] - } - - return [ - Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { [weak self] cell, _ in - self?.bind(cell: cell) - } - ), - ] - ), - Section( - id: "chart", - rows: [chartRow] - ), - ] - } - - private func bind(cell: MarketHeaderCell) { - let metricsType: MarketGlobalModule.MetricsType = .tvlInDefi - - cell.set( - title: metricsType.title, - description: metricsType.description, - imageMode: .remote(imageUrl: metricsType.imageUid.headerImageUrl) - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketListTvlDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketListTvlDecorator.swift deleted file mode 100644 index be232c4a2b..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketGlobalMetric/TvlInDefi/MarketListTvlDecorator.swift +++ /dev/null @@ -1,76 +0,0 @@ -import Foundation -import MarketKit - -class MarketListTvlDecorator { - typealias Item = DefiCoin - - private let service: MarketGlobalTvlMetricService - - init(service: MarketGlobalTvlMetricService) { - self.service = service - } -} - -extension MarketListTvlDecorator: IMarketListDecorator { - func listViewItem(item defiCoin: DefiCoin) -> MarketModule.ListViewItem { - let currency = service.currency - - var uid: String? - let iconUrl: String - let iconPlaceholderName: String - let name: String - - switch defiCoin.type { - case let .fullCoin(fullCoin): - uid = fullCoin.coin.uid - iconUrl = fullCoin.coin.imageUrl - iconPlaceholderName = "placeholder_circle_32" - name = fullCoin.coin.name - case let .defiCoin(defiName, logo): - iconUrl = logo - iconPlaceholderName = "placeholder_circle_32" - name = defiName - } - - var tvl: Decimal? - let diff: MarketModule.MarketDataValue - - switch service.marketPlatformField { - case .all: - tvl = defiCoin.tvl - - var tvlChange: Decimal? - switch service.priceChangePeriod { - case .byPeriod(.day1): tvlChange = defiCoin.tvlChange1d - case .byPeriod(.week1): tvlChange = defiCoin.tvlChange1w - case .byPeriod(.week2): tvlChange = defiCoin.tvlChange2w - case .byPeriod(.month1): tvlChange = defiCoin.tvlChange1m - case .byPeriod(.month3): tvlChange = defiCoin.tvlChange3m - case .byPeriod(.month6): tvlChange = defiCoin.tvlChange6m - case .byPeriod(.year1): tvlChange = defiCoin.tvlChange1y - default: () - } - - switch service.marketTvlField { - case .diff: diff = .diff(tvlChange) - case .value: diff = .valueDiff(CurrencyValue(currency: currency, value: defiCoin.tvl), tvlChange) - } - default: - tvl = defiCoin.chainTvls[service.marketPlatformField.chain] - diff = .diff(nil) - } - - 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 - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketHeaderCell.swift deleted file mode 100644 index 83d17f4e54..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketHeaderCell.swift +++ /dev/null @@ -1,66 +0,0 @@ -import UIKit - -class MarketHeaderCell: UITableViewCell { - static let height: CGFloat = 108 - - private let titleLabel = UILabel() - private let descriptionLabel = UILabel() - private let rightImageView = UIImageView() - - override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - backgroundColor = .clear - selectionStyle = .none - - contentView.addSubview(titleLabel) - titleLabel.snp.makeConstraints { make in - make.leading.equalToSuperview().inset(CGFloat.margin16) - make.top.equalToSuperview().inset(CGFloat.margin12) - } - - titleLabel.font = .headline1 - titleLabel.textColor = .themeLeah - - contentView.addSubview(descriptionLabel) - descriptionLabel.snp.makeConstraints { make in - make.leading.trailing.equalTo(titleLabel) - make.top.equalTo(titleLabel.snp.bottom).offset(CGFloat.margin8) - } - - descriptionLabel.numberOfLines = 0 - descriptionLabel.font = .subhead2 - descriptionLabel.textColor = .themeGray - - contentView.addSubview(rightImageView) - rightImageView.snp.makeConstraints { make in - make.leading.equalTo(titleLabel.snp.trailing).offset(CGFloat.margin16) - make.top.trailing.bottom.equalToSuperview() - make.width.equalTo(76) - } - } - - @available(*, unavailable) - public required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func set(title: String, description: String?, imageMode: ImageMode) { - titleLabel.text = title - descriptionLabel.text = description - - switch imageMode { - case let .local(image): - rightImageView.image = image - 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 deleted file mode 100644 index 9c5e425292..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListMarketFieldDecorator.swift +++ /dev/null @@ -1,66 +0,0 @@ -import MarketKit - -class MarketListMarketFieldDecorator { - typealias Item = MarketInfo - - private let service: IMarketListDecoratorService - private let statPage: StatPage - - var marketField: MarketModule.MarketField { - didSet { - service.onUpdate(index: marketField.rawValue) - - stat(page: statPage, event: .switchField(field: marketField.statField)) - } - } - - init(service: IMarketListDecoratorService, statPage: StatPage) { - self.service = service - self.statPage = statPage - - marketField = MarketModule.MarketField.allCases[service.initialIndex] - } -} - -extension MarketListMarketFieldDecorator: IMarketSingleSortHeaderDecorator { - var allFields: [String] { - MarketModule.MarketField.allCases.map(\.title) - } - - var currentFieldIndex: Int { - MarketModule.MarketField.allCases.firstIndex(of: marketField) ?? 0 - } - - func setCurrentField(index: Int) { - marketField = MarketModule.MarketField.allCases[index] - } -} - -extension MarketListMarketFieldDecorator: IMarketListDecorator { - func listViewItem(item marketInfo: MarketInfo) -> MarketModule.ListViewItem { - let currency = service.currency - - let price = marketInfo.price.flatMap { ValueFormatter.instance.formatFull(currency: currency, value: $0) } ?? "n/a".localized - - let dataValue: MarketModule.MarketDataValue - - switch marketField { - case .price: dataValue = .diff(marketInfo.priceChangeValue(type: service.priceChangeType)) - case .volume: dataValue = .volume(marketInfo.totalVolume.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized) - case .marketCap: dataValue = .marketCap(marketInfo.marketCap.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized) - } - - 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 - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewController.swift deleted file mode 100644 index fbfa742cdf..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewController.swift +++ /dev/null @@ -1,241 +0,0 @@ -import ComponentKit -import HUD -import RxCocoa -import RxSwift -import SectionsTableView -import ThemeKit -import UIKit - -protocol IMarketListViewModel { - var viewItemDataDriver: Driver { get } - var loadingDriver: Driver { get } - var syncErrorDriver: Driver { get } - var scrollToTopSignal: Signal { get } - func refresh() -} - -class MarketListViewController: ThemeViewController { - private let listViewModel: IMarketListViewModel - private let statPage: StatPage - private let disposeBag = DisposeBag() - - let tableView = SectionsTableView(style: .plain) - private let spinner = HUDActivityView.create(with: .medium24) - private let errorView = PlaceholderViewModule.reachabilityView() - private let refreshControl = UIRefreshControl() - - private var viewItems: [MarketModule.ListViewItem]? - - var viewController: UIViewController? { self } - var headerView: UITableViewHeaderFooterView? { nil } - var emptyView: UIView? { nil } - var refreshEnabled: Bool { true } - func topSections(loaded _: Bool) -> [SectionProtocol] { [] } - - init(listViewModel: IMarketListViewModel, statPage: StatPage) { - self.listViewModel = listViewModel - self.statPage = statPage - - super.init() - - if let watchViewModel = listViewModel as? IMarketListWatchViewModel { - subscribe(disposeBag, watchViewModel.favoriteDriver) { [weak self] in self?.showAddedToWatchlist() } - subscribe(disposeBag, watchViewModel.unfavoriteDriver) { [weak self] in self?.showRemovedFromWatchlist() } - subscribe(disposeBag, watchViewModel.failDriver) { error in HudHelper.instance.show(banner: .error(string: error.localized)) } - } - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - refreshControl.tintColor = .themeLeah - refreshControl.alpha = 0.6 - refreshControl.addTarget(self, action: #selector(onRefresh), for: .valueChanged) - - view.addSubview(tableView) - tableView.snp.makeConstraints { maker in - maker.edges.equalToSuperview() - } - - tableView.sectionHeaderTopPadding = 0 - tableView.separatorStyle = .none - tableView.backgroundColor = .clear - - tableView.sectionDataSource = self - - if let emptyView { - view.addSubview(emptyView) - emptyView.snp.makeConstraints { maker in - maker.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - 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, listViewModel.viewItemDataDriver) { [weak self] in self?.sync(viewItemData: $0) } - subscribe(disposeBag, listViewModel.loadingDriver) { [weak self] loading in - self?.spinner.isHidden = !loading - } - subscribe(disposeBag, listViewModel.syncErrorDriver) { [weak self] visible in - self?.errorView.isHidden = !visible - } - subscribe(disposeBag, listViewModel.scrollToTopSignal) { [weak self] in self?.scrollToTop() } - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - if refreshEnabled { - tableView.refreshControl = refreshControl - } - } - - @objc private func onRetry() { - refresh() - } - - @objc private func onRefresh() { - refresh() - - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in - self?.refreshControl.endRefreshing() - } - } - - private func refresh() { - listViewModel.refresh() - } - - private func sync(viewItemData: MarketModule.ListViewItemData?) { - viewItems = viewItemData?.viewItems - - if let viewItems, viewItems.isEmpty { - emptyView?.isHidden = false - } else { - emptyView?.isHidden = true - } - - if let viewItems, !viewItems.isEmpty { - tableView.bounces = true - } else { - tableView.bounces = false - } - - if let viewItemData { - tableView.reload(animated: viewItemData.softUpdate) - } else { - tableView.reload() - } - } - - func onSelect(viewItem: MarketModule.ListViewItem) { - guard let coinUid = viewItem.uid, let module = CoinPageModule.viewController(coinUid: coinUid) else { - HudHelper.instance.show(banner: .attention(string: "market.project_has_no_coin".localized)) - return - } - - viewController?.present(module, animated: true) - stat(page: statPage, event: .openCoin(coinUid: coinUid)) - } - - private func rowActions(index: Int) -> [RowAction] { - guard let watchListViewModel = listViewModel as? IMarketListWatchViewModel else { - return [] - } - - guard let isFavorite = watchListViewModel.isFavorite(index: index) else { - return [] - } - - let type: RowActionType - let iconName: String - let action: (UITableViewCell?) -> Void - - if isFavorite { - type = .destructive - iconName = "star_off_24" - action = { _ in - watchListViewModel.unfavorite(index: index) - } - } else { - type = .additive - iconName = "star_24" - action = { _ in - watchListViewModel.favorite(index: index) - } - } - - return [ - RowAction( - pattern: .icon(image: UIImage(named: iconName)?.withTintColor(type.iconColor), background: type.backgroundColor), - action: action - ), - ] - } - - private func scrollToTop() { - tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .bottom, animated: true) - } - - func showAddedToWatchlist() { - HudHelper.instance.show(banner: .addedToWatchlist) - } - - func showRemovedFromWatchlist() { - HudHelper.instance.show(banner: .removedFromWatchlist) - } -} - -extension MarketListViewController: SectionsDataSource { - func buildSections() -> [SectionProtocol] { - let headerState: ViewState - - if let headerView, let viewItems, !viewItems.isEmpty { - headerState = .static(view: headerView, height: .heightSingleLineCell) - } else { - headerState = .margin(height: 0) - } - - return topSections(loaded: viewItems != nil) + [ - Section( - id: "coins", - headerState: headerState, - footerState: .marginColor(height: .margin32, color: .clear), - rows: viewItems.map { viewItems in - viewItems.enumerated().map { index, viewItem in - MarketModule.marketListCell( - tableView: tableView, - backgroundStyle: .transparent, - listViewItem: viewItem, - isFirst: false, - isLast: index == viewItems.count - 1, - rowActionProvider: { [weak self] in - self?.rowActions(index: index) ?? [] - }, - action: { [weak self] in - self?.onSelect(viewItem: viewItem) - } - ) - } - } ?? [] - ), - ] - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewModel.swift deleted file mode 100644 index d579e67ab1..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListViewModel.swift +++ /dev/null @@ -1,116 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -protocol IMarketListService { - associatedtype Item - - var state: MarketListServiceState { get } - var statePublisher: AnyPublisher, Never> { get } - func refresh() -} - -protocol IMarketListCoinUidService { - func coinUid(index: Int) -> String? -} - -protocol IMarketListDecoratorService { - var initialIndex: Int { get } - var currency: Currency { get } - var priceChangeType: MarketModule.PriceChangeType { get } - func onUpdate(index: Int) -} - -protocol IMarketListDecorator { - associatedtype Item - - func listViewItem(item: Item) -> MarketModule.ListViewItem -} - -enum MarketListServiceState { - case loading - case loaded(items: [T], softUpdate: Bool, reorder: Bool) - case failed(error: Error) -} - -class MarketListViewModel { - private let service: Service - private let decorator: Decorator - private let itemLimit: Int? - private var cancellables = Set() - - private let viewItemDataRelay = BehaviorRelay(value: nil) - private let loadingRelay = BehaviorRelay(value: false) - private let syncErrorRelay = BehaviorRelay(value: false) - private let scrollToTopRelay = PublishRelay() - - init(service: Service, decorator: Decorator, itemLimit: Int? = nil) { - self.service = service - self.decorator = decorator - self.itemLimit = itemLimit - - service.statePublisher - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - sync(state: service.state) - } - - private func sync(state: MarketListServiceState) { - switch state { - case .loading: - viewItemDataRelay.accept(nil) - loadingRelay.accept(true) - syncErrorRelay.accept(false) - case let .loaded(items, softUpdate, reorder): - let limitedItems = itemLimit.map { Array(items.prefix(upTo: $0)) } ?? items - let data = MarketModule.ListViewItemData(viewItems: viewItems(items: Array(limitedItems)), softUpdate: softUpdate) - viewItemDataRelay.accept(data) - loadingRelay.accept(false) - syncErrorRelay.accept(false) - - if reorder { - scrollToTopRelay.accept(()) - } - case .failed: - viewItemDataRelay.accept(nil) - loadingRelay.accept(false) - syncErrorRelay.accept(true) - } - } - - private func viewItems(items: [Service.Item]) -> [MarketModule.ListViewItem] { - items.compactMap { item in - guard let item = item as? Decorator.Item else { - return nil - } - - return decorator.listViewItem(item: item) - } - } -} - -extension MarketListViewModel: IMarketListViewModel { - var viewItemDataDriver: Driver { - viewItemDataRelay.asDriver() - } - - var loadingDriver: Driver { - loadingRelay.asDriver() - } - - var syncErrorDriver: Driver { - syncErrorRelay.asDriver() - } - - 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 deleted file mode 100644 index 3e9c80407e..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketListWatchViewModel.swift +++ /dev/null @@ -1,69 +0,0 @@ -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -protocol IMarketListWatchViewModel: IMarketListViewModel { - var favoriteDriver: Driver { get } - var unfavoriteDriver: Driver { get } - var failDriver: Driver { get } - - func isFavorite(index: Int) -> Bool? - func favorite(index: Int) - func unfavorite(index: Int) -} - -class MarketListWatchViewModel: MarketListViewModel { - private let disposeBag = DisposeBag() - - private let watchlistToggleService: MarketWatchlistToggleService - - private let favoriteRelay = PublishRelay() - private let unfavoriteRelay = PublishRelay() - private let failRelay = PublishRelay() - - init(service: Service, watchlistToggleService: MarketWatchlistToggleService, decorator: Decorator) { - self.watchlistToggleService = watchlistToggleService - - super.init(service: service, decorator: decorator) - - subscribe(disposeBag, watchlistToggleService.statusObservable) { [weak self] in self?.handle(status: $0) } - } - - private func handle(status: MarketWatchlistToggleService.State) { - switch status { - case .favorite: - favoriteRelay.accept(()) - case .unfavorite: - unfavoriteRelay.accept(()) - case .fail: - failRelay.accept("watch_coin.fail_to_find_uuid") - } - } -} - -extension MarketListWatchViewModel: IMarketListWatchViewModel { - var favoriteDriver: Driver { - favoriteRelay.asDriver(onErrorJustReturn: ()) - } - - var unfavoriteDriver: Driver { - unfavoriteRelay.asDriver(onErrorJustReturn: ()) - } - - var failDriver: Driver { - failRelay.asDriver(onErrorJustReturn: "") - } - - func isFavorite(index: Int) -> Bool? { - watchlistToggleService.isFavorite(index: index) - } - - func favorite(index: Int) { - watchlistToggleService.favorite(index: index) - } - - 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 deleted file mode 100644 index 6aa7b796ff..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketList/MarketWatchlistToggleService.swift +++ /dev/null @@ -1,63 +0,0 @@ -import RxSwift - -class MarketWatchlistToggleService { - private let coinUidService: IMarketListCoinUidService - private let watchlistManager: WatchlistManager - private let statPage: StatPage - - private let statusSubject = PublishSubject() - - init(coinUidService: IMarketListCoinUidService, watchlistManager: WatchlistManager, statPage: StatPage) { - self.coinUidService = coinUidService - self.watchlistManager = watchlistManager - self.statPage = statPage - } -} - -extension MarketWatchlistToggleService { - var statusObservable: Observable { - statusSubject.asObservable() - } - - func isFavorite(index: Int) -> Bool? { - guard let coinUid = coinUidService.coinUid(index: index) else { - return nil - } - - return watchlistManager.isWatched(coinUid: coinUid) - } - - func favorite(index: Int) { - guard let coinUid = coinUidService.coinUid(index: index) else { - statusSubject.onNext(.fail) - return - } - - watchlistManager.add(coinUid: coinUid) - - statusSubject.onNext(.favorite) - - stat(page: statPage, event: .addToWatchlist(coinUid: coinUid)) - } - - func unfavorite(index: Int) { - guard let coinUid = coinUidService.coinUid(index: index) else { - statusSubject.onNext(.fail) - return - } - - watchlistManager.remove(coinUid: coinUid) - - statusSubject.onNext(.unfavorite) - - stat(page: statPage, event: .removeFromWatchlist(coinUid: coinUid)) - } -} - -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 867574b57c..8bbd522792 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketModule.swift @@ -1,146 +1,7 @@ -import ComponentKit import Foundation -import Kingfisher import MarketKit -import SectionsTableView -import ThemeKit -import UIKit - -enum RowActionType { - case additive - case destructive - - var iconColor: UIColor { - switch self { - case .additive: return .themeDark - case .destructive: return .themeClaude - } - } - - var backgroundColor: UIColor { - switch self { - case .additive: return .themeYellowD - case .destructive: return .themeRedD - } - } -} enum MarketModule { - static func viewController() -> UIViewController { - MarketViewController() - } - - static func marketListCell(tableView: UITableView, backgroundStyle: BaseThemeCell.BackgroundStyle, listViewItem: MarketModule.ListViewItem, isFirst: Bool, isLast: Bool, rowActionProvider: (() -> [RowAction])?, action: (() -> Void)?) -> RowProtocol { - CellBuilderNew.row( - rootElement: .hStack([ - .image32 { component in - component.imageView.contentMode = .scaleAspectFill - component.imageView.clipsToBounds = true - component.imageView.cornerRadius = listViewItem.iconShape.radius - component.imageView.layer.cornerCurve = .continuous - component.imageView.kf.setImage( - with: listViewItem.iconUrl.flatMap { URL(string: $0) }, - placeholder: UIImage(named: listViewItem.iconPlaceholderName), - options: [.onlyLoadFirstFrame] - ) - }, - .vStackCentered([ - .hStack([ - .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = listViewItem.leftPrimaryValue - }, - .text { component in - component.font = .body - component.textColor = .themeLeah - component.textAlignment = .right - component.setContentCompressionResistancePriority(.required, for: .horizontal) - component.text = listViewItem.rightPrimaryValue - }, - ]), - .margin(1), - .hStack([ - .badge { component in - if let badge = listViewItem.badge { - component.isHidden = false - component.badgeView.set(style: .small) - component.badgeView.text = badge - component.badgeView.change = listViewItem.badgeSecondaryValue - } else { - component.isHidden = true - } - }, - .margin4, - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = listViewItem.leftSecondaryValue - }, - .text { component in - component.setContentCompressionResistancePriority(.required, for: .horizontal) - component.setContentHuggingPriority(.required, for: .horizontal) - component.textAlignment = .right - let marketFieldData = marketFieldPreference(dataValue: listViewItem.rightSecondaryValue) - component.font = .subhead2 - component.textColor = marketFieldData.color - component.text = marketFieldData.value - }, - ]), - ]), - ]), - tableView: tableView, - id: "\(listViewItem.uid ?? "")-\(listViewItem.leftPrimaryValue)", - height: .heightDoubleLineCell, - autoDeselect: true, - rowActionProvider: rowActionProvider, - bind: { cell in - cell.set(backgroundStyle: backgroundStyle, isFirst: isFirst, isLast: isLast) - }, - action: action - ) - } - - static func marketFieldPreference(dataValue: MarketDataValue) -> (title: String?, value: String?, color: UIColor) { - let title: String? - let value: String? - let color: UIColor - - switch dataValue { - case let .valueDiff(currencyValue, diff): - title = nil - - 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 - } else { - value = "----" - color = .themeGray50 - } - case let .diff(diff): - title = nil - value = diff.flatMap { ValueFormatter.instance.format(percentValue: $0) } ?? "----" - if let diff { - color = diff.isSignMinus ? .themeLucian : .themeRemus - } else { - color = .themeGray50 - } - case let .volume(volume): - title = "market.top.volume.title".localized - value = volume - color = .themeGray - case let .marketCap(marketCap): - title = "market.top.market_cap.title".localized - value = marketCap - color = .themeGray - } - - return (title: title, value: value, color: color) - } -} - -extension MarketModule { enum SortBy: String, CaseIterable { case highestCap case lowestCap @@ -212,172 +73,9 @@ extension MarketModule { } } } - - enum TabOld: String, CaseIterable { - case overview - case posts - case watchlist - - var title: String { - switch self { - case .overview: return "market.category.overview".localized - case .posts: return "market.category.posts".localized - case .watchlist: return "market.category.watchlist".localized - } - } - } - - enum SortingField: Int, CaseIterable { - case highestCap - case lowestCap - case highestVolume - case lowestVolume - case topGainers - case topLosers - - var title: String { - switch self { - case .highestCap: return "market.top.highest_cap".localized - case .lowestCap: return "market.top.lowest_cap".localized - case .highestVolume: return "market.top.highest_volume".localized - case .lowestVolume: return "market.top.lowest_volume".localized - case .topGainers: return "market.top.top_gainers".localized - case .topLosers: return "market.top.top_losers".localized - } - } - - var raw: String { - switch self { - case .highestCap: return "highestCap" - case .lowestCap: return "lowestCap" - case .highestVolume: return "highestVolume" - case .lowestVolume: return "lowestVolume" - case .topGainers: return "topGainers" - case .topLosers: return "topLosers" - } - } - } - - enum MarketField: Int, CaseIterable { - case price - case marketCap - case volume - - var title: String { - switch self { - case .price: return "price".localized - case .marketCap: return "market.market_field.mcap".localized - case .volume: return "market.market_field.vol".localized - } - } - - var raw: String { - switch self { - case .price: return "price" - case .marketCap: return "marketCap" - case .volume: return "volume" - } - } - } - - enum MarketTop: Int, CaseIterable { - case top100 = 100 - case top200 = 200 - case top300 = 300 - - var title: String { - "\(rawValue)" - } - } - - enum PriceChangeType: Int, CaseIterable { - static let sortingTypes: [Self] = [.day, .week, .month] - - case day - case week - case week2 - case month - case month6 - case year - - var title: String { - switch self { - case .day: return "market.time_period.24h".localized - case .week: return "market.time_period.1w".localized - case .week2: return "market.time_period.2w".localized - case .month: return "market.time_period.1m".localized - case .month6: return "market.time_period.6m".localized - case .year: return "market.time_period.1y".localized - } - } - - var shortTitle: String { - switch self { - case .week: return "market.advanced_search.week.short".localized - case .month: return "market.advanced_search.month.short".localized - default: return "market.advanced_search.day.short".localized - } - } - } - - enum MarketTvlField: Int, CaseIterable { - case diff - case value - - var title: String { - switch self { - case .value: return "market.tvl.market_field.value".localized - case .diff: return "market.tvl.market_field.diff".localized - } - } - } - - enum MarketPlatformField: Int, CaseIterable { - case all - case ethereum - case solana - case binance - case avalanche - case terra - case fantom - case arbitrum - case polygon - - var chain: String { - switch self { - case .all: return "" - case .ethereum: return "Ethereum" - case .solana: return "Solana" - case .binance: return "Binance" - case .avalanche: return "Avalanche" - case .terra: return "Terra" - case .fantom: return "Fantom" - case .arbitrum: return "Arbitrum" - case .polygon: return "Polygon" - } - } - - var title: String { - switch self { - case .all: return "market.tvl.platform_field.all".localized - default: return chain - } - } - } } extension MarketKit.MarketInfo { - func priceChangeValue(type: MarketModule.PriceChangeType) -> Decimal? { - switch type { - case .day: return priceChange24h - case .week: return priceChange7d - case .week2: return priceChange14d - case .month: return priceChange30d - case .month6: return priceChange200d - case .year: return priceChange1y - } - } - func priceChangeValue(timePeriod: HsTimePeriod) -> Decimal? { switch timePeriod { case .day1: return priceChange24h @@ -402,17 +100,6 @@ extension MarketKit.MarketInfo { } extension MarketKit.DefiCoin { - func tvlChangeValue(type: MarketModule.PriceChangeType) -> Decimal? { - switch type { - case .day: return tvlChange1d - case .week: return tvlChange1w - case .week2: return tvlChange2w - case .month: return tvlChange1m - case .month6: return tvlChange6m - case .year: return tvlChange1y - } - } - func tvlChangeValue(timePeriod: HsTimePeriod) -> Decimal? { switch timePeriod { case .day1: return tvlChange1d @@ -464,26 +151,6 @@ extension [MarketKit.MarketInfo] { } } } - - func sorted(sortingField: MarketModule.SortingField, priceChangeType: MarketModule.PriceChangeType) -> [MarketKit.MarketInfo] { - sorted { lhsMarketInfo, rhsMarketInfo in - switch sortingField { - case .highestCap: return lhsMarketInfo.marketCap ?? 0 > rhsMarketInfo.marketCap ?? 0 - case .lowestCap: return lhsMarketInfo.marketCap ?? 0 < rhsMarketInfo.marketCap ?? 0 - case .highestVolume: return lhsMarketInfo.totalVolume ?? 0 > rhsMarketInfo.totalVolume ?? 0 - case .lowestVolume: return lhsMarketInfo.totalVolume ?? 0 < rhsMarketInfo.totalVolume ?? 0 - case .topGainers, .topLosers: - guard let rhsPriceChange = rhsMarketInfo.priceChangeValue(type: priceChangeType) else { - return true - } - guard let lhsPriceChange = lhsMarketInfo.priceChangeValue(type: priceChangeType) else { - return false - } - - return sortingField == .topGainers ? lhsPriceChange > rhsPriceChange : lhsPriceChange < rhsPriceChange - } - } - } } extension [MarketKit.TopPlatform] { @@ -520,52 +187,6 @@ extension [MarketKit.TopPlatform] { } } -extension MarketModule { // ViewModel Items - enum MarketDataValue { - case valueDiff(CurrencyValue?, Decimal?) - case diff(Decimal?) - case volume(String) - case marketCap(String) - } - - struct ListViewItem { - let uid: String? - let iconUrl: String? - let iconShape: IconShape - let iconPlaceholderName: String - let leftPrimaryValue: String - let leftSecondaryValue: String - let badge: String? - let badgeSecondaryValue: BadgeView.Change? - let rightPrimaryValue: String - let rightSecondaryValue: MarketDataValue - } - - struct ListViewItemData { - let viewItems: [ListViewItem] - let softUpdate: Bool - let scrollToTop: Bool - - init(viewItems: [ListViewItem], softUpdate: Bool = false, scrollToTop: Bool = false) { - self.viewItems = viewItems - self.softUpdate = softUpdate - self.scrollToTop = scrollToTop - } - } - - enum IconShape { - case square, round, full - - var radius: CGFloat { - switch self { - case .square: return .cornerRadius8 - case .round: return .cornerRadius16 - case .full: return 0 - } - } - } -} - extension HsTimePeriod { var title: String { switch self { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketListNftCollectionDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketListNftCollectionDecorator.swift deleted file mode 100644 index a1f401883c..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketListNftCollectionDecorator.swift +++ /dev/null @@ -1,53 +0,0 @@ -import Foundation -import MarketKit - -protocol IMarketListNftTopCollectionDecoratorService { - var timePeriod: HsTimePeriod { get } -} - -class MarketListNftCollectionDecorator { - typealias Item = NftCollectionItem - - private let service: IMarketListNftTopCollectionDecoratorService - - init(service: IMarketListNftTopCollectionDecoratorService) { - self.service = service - } -} - -extension MarketListNftCollectionDecorator: IMarketListDecorator { - func listViewItem(item: NftCollectionItem) -> MarketModule.ListViewItem { - let collection = item.collection - - var floorPriceString = "---" - - if let floorPrice = collection.floorPrice { - let coinValue = CoinValue(kind: .token(token: floorPrice.token), value: floorPrice.value) - if let value = ValueFormatter.instance.formatShort(coinValue: coinValue) { - floorPriceString = "market.top.floor_price".localized + " " + value - } - } - - var volumeString = "n/a".localized - let volume = collection.volumes[service.timePeriod] - let diff = collection.changes[service.timePeriod] - - 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 - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsModule.swift deleted file mode 100644 index 370119733d..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsModule.swift +++ /dev/null @@ -1,79 +0,0 @@ -import MarketKit -import ThemeKit -import UIKit - -enum MarketNftTopCollectionsModule { - static func viewController(timePeriod: HsTimePeriod) -> UIViewController { - let service = MarketNftTopCollectionsService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, timePeriod: timePeriod) - - let decorator = MarketListNftCollectionDecorator(service: service) - let viewModel = MarketNftTopCollectionsViewModel(service: service) - let listViewModel = MarketListViewModel(service: service, decorator: decorator, itemLimit: 100) - let headerViewModel = NftCollectionsMultiSortHeaderViewModel(service: service, decorator: decorator) - - let viewController = MarketNftTopCollectionsViewController(viewModel: viewModel, listViewModel: listViewModel, headerViewModel: headerViewModel) - - return ThemeNavigationController(rootViewController: viewController) - } - - enum SortType: Int, CaseIterable { - case highestVolume - case lowestVolume - case topGainers - case topLosers - - var title: String { - switch self { - case .highestVolume: return "market.top.highest_volume".localized - case .lowestVolume: return "market.top.lowest_volume".localized - case .topGainers: return "market.top.top_gainers".localized - case .topLosers: return "market.top.top_losers".localized - } - } - } - - static var selectorValues: [HsTimePeriod] { - [HsTimePeriod.day1, - HsTimePeriod.week1, - HsTimePeriod.month1] - } -} - -extension NftTopCollection { - var uid: String { - "\(blockchainType.uid)-\(providerUid)" - } -} - -extension [NftTopCollection] { - func sorted(sortType: MarketNftTopCollectionsModule.SortType, timePeriod: HsTimePeriod) -> [NftTopCollection] { - sorted { lhsCollection, rhsCollection in - let lhsVolume = lhsCollection.volumes[timePeriod]?.value - let rhsVolume = rhsCollection.volumes[timePeriod]?.value - - let lhsChange = lhsCollection.changes[timePeriod] - let rhsChange = rhsCollection.changes[timePeriod] - - switch sortType { - case .highestVolume, .lowestVolume: - guard let lhsVolume else { - return true - } - guard let rhsVolume else { - return false - } - - return sortType == .highestVolume ? lhsVolume > rhsVolume : lhsVolume < rhsVolume - case .topGainers, .topLosers: - guard let lhsChange else { - return true - } - guard let rhsChange else { - return false - } - - return sortType == .topGainers ? lhsChange > rhsChange : lhsChange < rhsChange - } - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsService.swift deleted file mode 100644 index 9c886791ff..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsService.swift +++ /dev/null @@ -1,87 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -struct NftCollectionItem { - let index: Int - let collection: NftTopCollection -} - -class MarketNftTopCollectionsService { - typealias Item = NftCollectionItem - - private let disposeBag = DisposeBag() - private var tasks = Set() - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - - private var internalState: MarketListServiceState = .loading - - @PostPublished private(set) var state: MarketListServiceState = .loading - - var sortType: MarketNftTopCollectionsModule.SortType = .highestVolume { didSet { syncIfPossible() } } - var timePeriod: HsTimePeriod { didSet { syncIfPossible() } } - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, timePeriod: HsTimePeriod) { - self.marketKit = marketKit - self.currencyManager = currencyManager - self.timePeriod = timePeriod - - sync() - } - - private func sync() { - tasks = Set() - - if case .failed = state { - state = .loading - } - - Task { [weak self, marketKit] in - do { - let collections = try await marketKit.nftTopCollections() - self?.internalState = .loaded(items: collections, softUpdate: false, reorder: false) - self?.sync(collections: collections) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } - - private func sync(collections: [NftTopCollection], reorder: Bool = false) { - let sortedCollections = collections.sorted(sortType: sortType, timePeriod: timePeriod) - let items = sortedCollections.enumerated().map { NftCollectionItem(index: $0 + 1, collection: $1) } - state = .loaded(items: items, softUpdate: false, reorder: reorder) - } - - private func syncIfPossible() { - 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 let .loaded(collections, _, _) = internalState else { - return nil - } - - return collections.first { $0.uid == uid } - } - - func refresh() { - sync() - } -} - -extension MarketNftTopCollectionsService: IMarketListNftTopCollectionDecoratorService {} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewController.swift deleted file mode 100644 index 3860c9eeba..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewController.swift +++ /dev/null @@ -1,71 +0,0 @@ -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketNftTopCollectionsViewController: MarketListViewController { - private let viewModel: MarketNftTopCollectionsViewModel - private let multiSortHeaderView: MarketMultiSortHeaderView - - override var viewController: UIViewController? { self } - override var headerView: UITableViewHeaderFooterView? { multiSortHeaderView } - override var refreshEnabled: Bool { false } - - init(viewModel: MarketNftTopCollectionsViewModel, listViewModel: IMarketListViewModel, headerViewModel: NftCollectionsMultiSortHeaderViewModel) { - self.viewModel = viewModel - multiSortHeaderView = MarketMultiSortHeaderView(viewModel: headerViewModel) - - super.init(listViewModel: listViewModel, statPage: .topNftCollections) - - multiSortHeaderView.viewController = self - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: MarketHeaderCell.self) - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded _: Bool) -> [SectionProtocol] { - [ - Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { cell, _ in - cell.set( - title: "top_nft_collections.title".localized, - description: "top_nft_collections.description".localized, - imageMode: .remote(imageUrl: "nft".headerImageUrl) - ) - } - ), - ] - ), - ] - } - - override func onSelect(viewItem: MarketModule.ListViewItem) { - guard let uid = viewItem.uid, let topCollection = viewModel.topCollection(uid: uid) else { - return - } - - if let module = NftCollectionModule.viewController(blockchainType: topCollection.blockchainType, providerCollectionUid: topCollection.providerUid) { - present(ThemeNavigationController(rootViewController: module), animated: true) - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewModel.swift deleted file mode 100644 index a4c47bf378..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/MarketNftTopCollectionsViewModel.swift +++ /dev/null @@ -1,13 +0,0 @@ -import MarketKit - -class MarketNftTopCollectionsViewModel { - private let service: MarketNftTopCollectionsService - - init(service: MarketNftTopCollectionsService) { - self.service = service - } - - 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 deleted file mode 100644 index b79fe6cf3c..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketNftTopCollections/NftCollectionsMultiSortHeaderViewModel.swift +++ /dev/null @@ -1,47 +0,0 @@ -import MarketKit - -class NftCollectionsMultiSortHeaderViewModel { - private let service: MarketNftTopCollectionsService - private let decorator: MarketListNftCollectionDecorator - - init(service: MarketNftTopCollectionsService, decorator: MarketListNftCollectionDecorator) { - self.service = service - self.decorator = decorator - } -} - -extension NftCollectionsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel { - var sortItems: [String] { - MarketNftTopCollectionsModule.SortType.allCases.map(\.title) - } - - var sortIndex: Int { - MarketNftTopCollectionsModule.SortType.allCases.firstIndex(of: service.sortType) ?? 0 - } - - var leftSelectorItems: [String] { - [] - } - - var leftSelectorIndex: Int { - 0 - } - - var rightSelectorItems: [String] { - MarketNftTopCollectionsModule.selectorValues.map(\.shortTitle) - } - - var rightSelectorIndex: Int { - MarketNftTopCollectionsModule.selectorValues.firstIndex(of: service.timePeriod) ?? 0 - } - - func onSelectSort(index: Int) { - service.sortType = MarketNftTopCollectionsModule.SortType.allCases[index] - } - - 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 deleted file mode 100644 index 176df3590a..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/BaseMarketOverviewTopListDataSource.swift +++ /dev/null @@ -1,133 +0,0 @@ -import Chart -import ComponentKit -import RxCocoa -import RxSwift -import SectionsTableView -import UIKit - -protocol IBaseMarketOverviewTopListViewModel { - var listViewItemsDriver: Driver<[MarketModule.ListViewItem]?> { get } - var selectorTitles: [String] { get } - var selectorIndex: Int { get } - func onSelect(selectorIndex: Int) -} - -class BaseMarketOverviewTopListDataSource { - private let topListViewModel: IBaseMarketOverviewTopListViewModel - weak var presentDelegate: IPresentDelegate? - private let rightSelectorMode: MarketOverviewHeaderCell.ButtonMode - private let imageName: String - private let title: String - private let disposeBag = DisposeBag() - - private let listViewItemsRelay = BehaviorRelay<[MarketModule.ListViewItem]?>(value: nil) - - init(topListViewModel: IBaseMarketOverviewTopListViewModel, presentDelegate: IPresentDelegate, rightSelectorMode: MarketOverviewHeaderCell.ButtonMode, imageName: String, title: String) { - self.topListViewModel = topListViewModel - self.presentDelegate = presentDelegate - self.rightSelectorMode = rightSelectorMode - self.imageName = imageName - self.title = title - - subscribe(disposeBag, topListViewModel.listViewItemsDriver) { [weak self] listViewItems in - self?.listViewItemsRelay.accept(listViewItems) - } - } - - 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) - } - ) - } - } - - 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 - ) - } - - func didTapSeeAll() {} - - func onSelect(listViewItem _: MarketModule.ListViewItem) {} -} - -extension BaseMarketOverviewTopListDataSource: IMarketOverviewDataSource { - var isReady: Bool { - listViewItemsRelay.value != nil - } - - var updateObservable: Observable { - listViewItemsRelay.map { _ in () } - } - - private func bind(cell: MarketOverviewHeaderCell) { - cell.set(backgroundStyle: .transparent) - - cell.buttonMode = rightSelectorMode - cell.set(values: topListViewModel.selectorTitles) - cell.setSelected(index: topListViewModel.selectorIndex) - cell.onSelect = { [weak self] index in - self?.topListViewModel.onSelect(selectorIndex: index) - } - cell.onTapTitle = { [weak self] in self?.didTapSeeAll() } - - cell.titleImage = UIImage(named: imageName) - cell.title = title - } - - func sections(tableView: SectionsTableView) -> [SectionProtocol] { - guard let listViewItems = listViewItemsRelay.value else { - return [] - } - - 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) - } - ), - ] - ) - - 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() - } - ), - ] - ) - - sections.append(headerSection) - sections.append(listSection) - - return sections - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryCell.swift deleted file mode 100644 index 79a892a069..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryCell.swift +++ /dev/null @@ -1,100 +0,0 @@ -import MarketKit -import SnapKit -import UIKit - -class MarketOverviewCategoryCell: UITableViewCell { - static let cellHeight: CGFloat = MarketCategoryView.height + 2 * .margin16 - - var onSelect: ((String) -> Void)? - - var viewItems = [MarketOverviewCategoryViewModel.ViewItem]() { - didSet { - build() - } - } - - private let scrollView = UIScrollView() - private let stackView = UIStackView() - private let leadingView = UIView() - private let trailingView = UIView() - - override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - backgroundColor = .clear - selectionStyle = .none - - contentView.addSubview(scrollView) - scrollView.snp.makeConstraints { make in - make.leading.trailing.equalToSuperview().inset(CGFloat.margin12) - make.top.bottom.equalToSuperview().inset(CGFloat.margin16) - } - - scrollView.isPagingEnabled = true - scrollView.clipsToBounds = false - scrollView.showsHorizontalScrollIndicator = false - - scrollView.addSubview(stackView) - stackView.snp.makeConstraints { make in - make.leading.trailing.equalTo(scrollView).inset(-CGFloat.margin4) - make.top.bottom.equalTo(scrollView) - make.height.equalTo(scrollView) - } - - stackView.spacing = .margin8 - - leadingView.snp.makeConstraints { make in - make.width.equalTo(0) - } - trailingView.snp.makeConstraints { make in - make.width.equalTo(0) - } - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func build() { - for view in stackView.arrangedSubviews { - stackView.removeArrangedSubview(view) - view.removeFromSuperview() - } - - stackView.addArrangedSubview(leadingView) - - var bufferView: UIView? - - for (index, viewItem) in viewItems.enumerated() { - let view = MarketCategoryView() - view.set(viewItem: viewItem) - view.onTap = { [weak self] in - self?.onSelect?(viewItem.uid) - } - - if let _bufferView = bufferView { - addPage(views: [_bufferView, view]) - bufferView = nil - } else if index == viewItems.count - 1 { - addPage(views: [view, UIView()]) - } else { - bufferView = view - } - } - - stackView.addArrangedSubview(trailingView) - } - - private func addPage(views: [UIView]) { - let stackView = UIStackView(arrangedSubviews: views) - stackView.spacing = .margin8 - stackView.distribution = .fillEqually - - self.stackView.addArrangedSubview(stackView) - - stackView.snp.makeConstraints { make in - make.width.equalTo(scrollView).offset(-CGFloat.margin8) - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryDataSource.swift deleted file mode 100644 index ceebf367ac..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryDataSource.swift +++ /dev/null @@ -1,84 +0,0 @@ -import RxCocoa -import RxSwift -import SectionsTableView -import UIKit - -class MarketOverviewCategoryDataSource { - private let viewModel: MarketOverviewCategoryViewModel - weak var presentDelegate: IPresentDelegate? - private let disposeBag = DisposeBag() - - private let viewItemsRelay = BehaviorRelay<[MarketOverviewCategoryViewModel.ViewItem]?>(value: nil) - - private let categoryCell = MarketOverviewCategoryCell() - - init(viewModel: MarketOverviewCategoryViewModel, presentDelegate: IPresentDelegate) { - self.viewModel = viewModel - self.presentDelegate = presentDelegate - - subscribe(disposeBag, viewModel.viewItemsDriver) { [weak self] viewItems in - self?.viewItemsRelay.accept(viewItems) - - if let viewItems { - self?.categoryCell.viewItems = viewItems - } - } - - categoryCell.onSelect = { [weak self] uid in - guard let category = viewModel.category(uid: uid) else { - return - } - - let viewController = MarketCategoryModule.viewController(category: category) - self?.presentDelegate?.present(viewController: viewController) - - stat(page: .marketOverview, event: .openCategory(categoryUid: uid)) - } - } - - private func bind(cell: MarketOverviewHeaderCell) { - cell.set(backgroundStyle: .transparent) - cell.buttonMode = .none - cell.titleImage = UIImage(named: "categories_20") - cell.title = "market.top.section.header.sectors".localized - cell.onTapTitle = nil - } -} - -extension MarketOverviewCategoryDataSource: IMarketOverviewDataSource { - var isReady: Bool { - viewItemsRelay.value != nil - } - - var updateObservable: Observable { - viewItemsRelay.map { _ in () } - } - - func sections(tableView _: SectionsTableView) -> [SectionProtocol] { - [ - Section( - id: "categories_header", - rows: [ - Row( - id: "categories_header_cell", - height: .heightCell48, - bind: { [weak self] cell, _ in - self?.bind(cell: cell) - } - ), - ] - ), - Section( - id: "categories", - footerState: .margin(height: .margin32), - rows: [ - StaticRow( - cell: categoryCell, - id: "categories", - height: MarketOverviewCategoryCell.cellHeight - ), - ] - ), - ] - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryService.swift deleted file mode 100644 index b5c66a5e2a..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryService.swift +++ /dev/null @@ -1,53 +0,0 @@ -import Combine -import Foundation -import MarketKit -import RxRelay -import RxSwift - -class MarketOverviewCategoryService { - private let baseService: MarketOverviewService - private var cancellables = Set() - - let marketTop: MarketModule.MarketTop = .top100 - let listType: MarketOverviewTopCoinsService.ListType - - private let categoriesRelay = PublishRelay<[CoinCategory]?>() - private(set) var categories: [CoinCategory]? { - didSet { - categoriesRelay.accept(categories) - } - } - - init(listType: MarketOverviewTopCoinsService.ListType, baseService: MarketOverviewService) { - self.listType = listType - self.baseService = baseService - - baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - sync() - } - - private func sync(state: DataStatus? = nil) { - let state = state ?? baseService.state - - categories = state.data.map { item in - item.marketOverview.coinCategories - } - } -} - -extension MarketOverviewCategoryService { - var categoriesObservable: Observable<[CoinCategory]?> { - categoriesRelay.asObservable() - } - - var currency: Currency { - baseService.currency - } - - 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 deleted file mode 100644 index d7d81ce344..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/Category/MarketOverviewCategoryViewModel.swift +++ /dev/null @@ -1,85 +0,0 @@ -import MarketKit -import RxCocoa -import RxRelay -import RxSwift -import UIKit - -class MarketOverviewCategoryViewModel { - private let service: MarketOverviewCategoryService - private let disposeBag = DisposeBag() - - private let viewItemsRelay = BehaviorRelay<[ViewItem]?>(value: nil) - - init(service: MarketOverviewCategoryService) { - self.service = service - - subscribe(disposeBag, service.categoriesObservable) { [weak self] in self?.sync(categories: $0) } - - sync(categories: service.categories) - } - - private func sync(categories: [CoinCategory]?) { - viewItemsRelay.accept(categories.map { $0.map { viewItem(category: $0) } }) - } - - private func viewItem(category: CoinCategory) -> ViewItem { - var marketCap: String? - if let amount = category.marketCap { - marketCap = ValueFormatter.instance.formatShort(currency: service.currency, value: amount) - } else { - marketCap = "----" - } - - let diff = category.diff(timePeriod: .day1) - let diffString: String? = diff.flatMap { - ValueFormatter.instance.format(percentValue: $0) - } - - let diffType: DiffType = (diff?.isSignMinus ?? true) ? .down : .up - - return ViewItem( - uid: category.uid, - imageUrl: category.imageUrl, - name: category.name, - marketCap: marketCap, - diff: diffString, - diffType: diffType - ) - } -} - -extension MarketOverviewCategoryViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { - viewItemsRelay.asDriver() - } - - func category(uid: String) -> CoinCategory? { - service.category(uid: uid) - } - - var marketTop: MarketModule.MarketTop { service.marketTop } - var listType: MarketOverviewTopCoinsService.ListType { service.listType } -} - -extension MarketOverviewCategoryViewModel { - struct ViewItem { - let uid: String - let imageUrl: String - let name: String - let marketCap: String? - let diff: String? - let diffType: DiffType - } - - enum DiffType { - case down - case up - - var textColor: UIColor { - switch self { - case .up: return .themeRemus - case .down: return .themeLucian - } - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalDataSource.swift deleted file mode 100644 index 8116c07e43..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalDataSource.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Chart -import ComponentKit -import RxCocoa -import RxSwift -import SectionsTableView -import UIKit - -class MarketOverviewGlobalDataSource { - private let viewModel: MarketOverviewGlobalViewModel - weak var presentDelegate: IPresentDelegate? - private let disposeBag = DisposeBag() - - private let marketMetricsCell: MarketOverviewMetricsCell - private let marketMetricsRow: StaticRow - - private let viewItemRelay = BehaviorRelay(value: nil) - - init(viewModel: MarketOverviewGlobalViewModel, presentDelegate: IPresentDelegate) { - self.viewModel = viewModel - self.presentDelegate = presentDelegate - - marketMetricsCell = MarketOverviewMetricsCell(chartConfiguration: ChartConfiguration.smallPreviewChart, presentDelegate: presentDelegate) - marketMetricsRow = StaticRow( - 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 { - viewItemRelay.map { _ in () } - } - - func sections(tableView _: SectionsTableView) -> [SectionProtocol] { - guard let viewItem = viewItemRelay.value else { - return [] - } - - marketMetricsRow.onReady = { [weak self] in - self?.marketMetricsCell.set(viewItem: viewItem) - } - - return [ - Section( - 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 deleted file mode 100644 index f2509689cb..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalService.swift +++ /dev/null @@ -1,111 +0,0 @@ -import Combine -import Foundation -import MarketKit -import RxRelay -import RxSwift - -class MarketOverviewGlobalService { - private let baseService: MarketOverviewService - private var cancellables = Set() - - private let globalMarketDataRelay = PublishRelay() - private(set) var globalMarketData: GlobalMarketData? { - didSet { - globalMarketDataRelay.accept(globalMarketData) - } - } - - init(baseService: MarketOverviewService) { - self.baseService = baseService - - baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - sync() - } - - private func sync(state: DataStatus? = nil) { - let state = state ?? baseService.state - - globalMarketData = state.data.map { item in - globalMarketData(globalMarketPoints: item.marketOverview.globalMarketPoints) - } - } - - private func globalMarketData(globalMarketPoints: [GlobalMarketPoint]) -> GlobalMarketData { - let marketCapPointItems = globalMarketPoints.map { - GlobalMarketPointItem(timestamp: $0.timestamp, amount: $0.marketCap) - } - let volume24hPointItems = globalMarketPoints.map { - GlobalMarketPointItem(timestamp: $0.timestamp, amount: $0.volume24h) - } - let defiMarketCapPointItems = globalMarketPoints.map { - GlobalMarketPointItem(timestamp: $0.timestamp, amount: $0.defiMarketCap) - } - let tvlPointItems = globalMarketPoints.map { - GlobalMarketPointItem(timestamp: $0.timestamp, amount: $0.tvl) - } - - return GlobalMarketData( - 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 - ) - } - - private func amount(pointItems: [GlobalMarketPointItem]) -> CurrencyValue? { - guard let lastAmount = pointItems.last?.amount else { - return nil - } - - return CurrencyValue(currency: currency, value: lastAmount) - } - - private func diff(pointItems: [GlobalMarketPointItem]) -> Decimal? { - guard let firstAmount = pointItems.first?.amount, let lastAmount = pointItems.last?.amount, firstAmount != 0 else { - return nil - } - - return (lastAmount - firstAmount) * 100 / firstAmount - } -} - -extension MarketOverviewGlobalService { - var globalMarketDataObservable: Observable { - globalMarketDataRelay.asObservable() - } - - var currency: Currency { - baseService.currency - } -} - -extension MarketOverviewGlobalService { - struct GlobalMarketData { - let marketCap: GlobalMarketItem - let volume24h: GlobalMarketItem - let defiMarketCap: GlobalMarketItem - let defiTvl: GlobalMarketItem - } - - struct GlobalMarketItem { - let amount: CurrencyValue? - let diff: Decimal? - let pointItems: [GlobalMarketPointItem] - } - - struct GlobalMarketPointItem { - 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 deleted file mode 100644 index 12e93973ca..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/GlobalMarket/MarketOverviewGlobalViewModel.swift +++ /dev/null @@ -1,92 +0,0 @@ -import Chart -import Foundation -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -class MarketOverviewGlobalViewModel { - private let service: MarketOverviewGlobalService - private let disposeBag = DisposeBag() - - private let viewItemRelay = BehaviorRelay(value: nil) - - init(service: MarketOverviewGlobalService) { - self.service = service - - subscribe(disposeBag, service.globalMarketDataObservable) { [weak self] in self?.sync(globalMarketData: $0) } - - sync(globalMarketData: service.globalMarketData) - } - - private func sync(globalMarketData: MarketOverviewGlobalService.GlobalMarketData?) { - viewItemRelay.accept(globalMarketData.map { viewItem(globalMarketData: $0) }) - } - - 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) - ) - } - - private func chartViewItem(item: MarketOverviewGlobalService.GlobalMarketItem) -> ChartViewItem { - let value = item.amount.flatMap { ValueFormatter.instance.formatShort(currency: $0.currency, value: $0.value) } - - var chartData: ChartData? - var trend: MovementTrend = .neutral - - let pointItems = item.pointItems - - if let firstPointItem = pointItems.first, let lastPointItem = pointItems.last { - let chartItems: [ChartItem] = pointItems.map { - let item = ChartItem(timestamp: $0.timestamp) - item.added(name: ChartData.rate, value: $0.amount) - return item - } - - if firstPointItem.amount > lastPointItem.amount { - trend = .down - } else if firstPointItem.amount < lastPointItem.amount { - trend = .up - } - - chartData = ChartData( - items: chartItems, - startWindow: firstPointItem.timestamp, - endWindow: lastPointItem.timestamp - ) - } - - return ChartViewItem( - 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 - let defiCap: ChartViewItem - let defiTvl: ChartViewItem - } - - struct ChartViewItem { - let value: String? - let diff: Decimal? - let chartData: ChartData? - let chartTrend: MovementTrend - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketCategoryView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketCategoryView.swift deleted file mode 100644 index d1e998096f..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketCategoryView.swift +++ /dev/null @@ -1,100 +0,0 @@ -import UIKit - -class MarketCategoryView: UIView { - static let height: CGFloat = 140 - - private let imageView = UIImageView() - private let nameLabel = UILabel() - private let stackView = UIStackView() - private let marketCapLabel = UILabel() - private let diffLabel = UILabel() - - private let button = UIButton() - - var onTap: (() -> Void)? { - didSet { - button.isUserInteractionEnabled = onTap != nil - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - - backgroundColor = .themeLawrence - cornerRadius = .cornerRadius12 - layer.cornerCurve = .continuous - - addSubview(button) - button.snp.makeConstraints { maker in - maker.edges.equalToSuperview() - } - - button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside) - button.isUserInteractionEnabled = false - - addSubview(imageView) - imageView.snp.makeConstraints { maker in - maker.top.trailing.equalToSuperview() - } - - addSubview(stackView) - stackView.snp.makeConstraints { maker in - maker.leading.bottom.equalToSuperview().inset(CGFloat.margin12) - } - - stackView.axis = .horizontal - stackView.spacing = .margin6 - - stackView.addArrangedSubview(marketCapLabel) - marketCapLabel.font = .caption - marketCapLabel.textColor = .themeGray - - stackView.addArrangedSubview(diffLabel) - diffLabel.font = .caption - - addSubview(nameLabel) - nameLabel.snp.makeConstraints { maker in - maker.leading.trailing.equalToSuperview().inset(CGFloat.margin12) - maker.bottom.equalTo(stackView.snp.top).offset(-CGFloat.margin8) - } - - nameLabel.numberOfLines = 0 - nameLabel.font = .subhead1 - nameLabel.textColor = .themeLeah - - updateUI() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - updateUI() - } - - @objc private func didTapButton() { - onTap?() - } - - private func updateUI() { - button.setBackgroundColor(color: .themeLawrencePressed, forState: .highlighted) - } - - func set(viewItem: MarketOverviewCategoryViewModel.ViewItem) { - imageView.setImage(withUrlString: viewItem.imageUrl, placeholder: nil) - - nameLabel.text = viewItem.name - - marketCapLabel.text = viewItem.marketCap - diffLabel.text = viewItem.diff - diffLabel.textColor = viewItem.diffType.textColor - - nameLabel.snp.updateConstraints { maker in - maker.bottom.equalTo(stackView.snp.top).offset(viewItem.marketCap == nil ? 0 : -CGFloat.margin8) - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewHeaderCell.swift deleted file mode 100644 index b4f5c112ab..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewHeaderCell.swift +++ /dev/null @@ -1,141 +0,0 @@ -import ComponentKit -import SnapKit -import UIKit - -class MarketOverviewHeaderCell: BaseThemeCell { - private let leftImage = ImageComponent(size: .iconSize24) - private let titleText = TextComponent() - private let buttonWrapper = UIView() - private let rightButton = SelectorButton() - private let seeAllButton = SecondaryButton() - - var onSelect: ((Int) -> Void)? { - didSet { - rightButton.onSelect = onSelect - } - } - - var onSeeAll: (() -> Void)? - var onTapTitle: (() -> Void)? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - wrapperView.addSubview(leftImage) - leftImage.snp.makeConstraints { maker in - maker.leading.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - } - - wrapperView.addSubview(titleText) - titleText.snp.makeConstraints { maker in - maker.leading.equalTo(leftImage.snp.trailing).offset(CGFloat.margin16) - maker.centerY.equalToSuperview() - } - - titleText.font = .body - titleText.textColor = .themeLeah - - wrapperView.addSubview(buttonWrapper) - buttonWrapper.snp.makeConstraints { maker in - maker.leading.equalTo(titleText.snp.trailing).offset(CGFloat.margin16) - maker.trailing.equalToSuperview().inset(CGFloat.margin16) - maker.top.bottom.equalToSuperview() - } - - let leftButton = UIButton() - wrapperView.addSubview(leftButton) - leftButton.snp.makeConstraints { maker in - maker.edges.equalTo(titleText) - } - - leftButton.addTarget(self, action: #selector(onTapLeftView), for: .touchUpInside) - - buttonWrapper.addSubview(rightButton) - rightButton.snp.makeConstraints { maker in - maker.leading.trailing.equalToSuperview() - maker.centerY.equalToSuperview() - maker.height.equalTo(28) - } - - buttonWrapper.addSubview(seeAllButton) - seeAllButton.snp.makeConstraints { maker in - maker.leading.trailing.equalToSuperview() - maker.centerY.equalToSuperview() - maker.height.equalTo(28) - } - - seeAllButton.isHidden = true - seeAllButton.set(style: .default) - seeAllButton.setTitle("market.top.section.header.see_all".localized, for: .normal) - seeAllButton.addTarget(self, action: #selector(onTapSeeAll), for: .touchUpInside) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc private func onTapLeftView() { - onTapTitle?() - } - - var title: String? { - get { titleText.text } - set { - titleText.text = newValue - } - } - - var titleImage: UIImage? { - get { leftImage.imageView.image } - set { leftImage.imageView.image = newValue } - } - - var currentIndex: Int { - rightButton.currentIndex - } - - func set(values: [String]) { - rightButton.set(items: values) - } - - func setSelected(index: Int) { - rightButton.setSelected(index: index) - } - - @objc func onTapSeeAll() { - onSeeAll?() - } - - var buttonMode: ButtonMode = .seeAll { - didSet { - rightButton.isHidden = true - seeAllButton.isHidden = true - rightButton.setContentHuggingPriority(.defaultLow, for: .horizontal) - seeAllButton.setContentHuggingPriority(.defaultLow, for: .horizontal) - rightButton.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) - seeAllButton.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) - - switch buttonMode { - case .selector: - rightButton.isHidden = false - rightButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) - seeAllButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - case .seeAll: - seeAllButton.isHidden = false - seeAllButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) - rightButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - case .none: return - } - } - } -} - -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 deleted file mode 100644 index e515eba40e..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewMetricsCell.swift +++ /dev/null @@ -1,123 +0,0 @@ -import Chart -import ComponentKit -import HUD -import SnapKit -import ThemeKit -import UIKit - -class MarketOverviewMetricsCell: UITableViewCell { - static let cellHeight: CGFloat = MarketCardView.height + 2 * .margin16 - - private weak var presentDelegate: IPresentDelegate? - - private let totalMarketCapView: MarketCardView - private let volume24hView: MarketCardView - private let deFiCapView: MarketCardView - private let deFiTvlView: MarketCardView - - init(chartConfiguration: ChartConfiguration, presentDelegate: IPresentDelegate) { - self.presentDelegate = presentDelegate - - totalMarketCapView = MarketCardView(configuration: chartConfiguration) - volume24hView = MarketCardView(configuration: chartConfiguration) - deFiCapView = MarketCardView(configuration: chartConfiguration) - deFiTvlView = MarketCardView(configuration: chartConfiguration) - - super.init(style: .default, reuseIdentifier: nil) - - backgroundColor = .clear - selectionStyle = .none - - let scrollView = UIScrollView() - - contentView.addSubview(scrollView) - scrollView.snp.makeConstraints { make in - make.leading.trailing.equalToSuperview().inset(CGFloat.margin12) - make.top.bottom.equalToSuperview().inset(CGFloat.margin16) - } - - scrollView.isPagingEnabled = true - scrollView.clipsToBounds = false - scrollView.showsHorizontalScrollIndicator = false - - let firstStack = UIStackView(arrangedSubviews: [totalMarketCapView, volume24hView]) - firstStack.spacing = .margin8 - firstStack.distribution = .fillEqually - - let secondStack = UIStackView(arrangedSubviews: [deFiCapView, deFiTvlView]) - secondStack.spacing = .margin8 - secondStack.distribution = .fillEqually - - let leadingView = UIView() - let trailingView = UIView() - - let stackView = UIStackView(arrangedSubviews: [ - leadingView, - firstStack, - secondStack, - trailingView, - ]) - - scrollView.addSubview(stackView) - stackView.snp.makeConstraints { make in - make.leading.trailing.equalTo(scrollView).inset(-CGFloat.margin4) - make.top.bottom.equalTo(scrollView) - make.height.equalTo(scrollView) - } - - stackView.spacing = .margin8 - - leadingView.snp.makeConstraints { make in - make.width.equalTo(0) - } - trailingView.snp.makeConstraints { make in - make.width.equalTo(0) - } - firstStack.snp.makeConstraints { make in - make.width.equalTo(scrollView).offset(-CGFloat.margin8) - } - secondStack.snp.makeConstraints { make in - make.width.equalTo(scrollView).offset(-CGFloat.margin8) - } - - totalMarketCapView.onTap = { [weak self] in self?.onTap(metricType: .totalMarketCap) } - volume24hView.onTap = { [weak self] in self?.onTap(metricType: .volume24h) } - deFiCapView.onTap = { [weak self] in self?.onTap(metricType: .defiCap) } - deFiTvlView.onTap = { [weak self] in self?.onTap(metricType: .tvlInDefi) } - - totalMarketCapView.title = "market.total_market_cap".localized - volume24hView.title = "market.24h_volume".localized - deFiCapView.title = "market.defi_cap".localized - deFiTvlView.title = "market.defi_tvl".localized - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func onTap(metricType: MarketGlobalModule.MetricsType) { - let viewController = MarketGlobalMetricModule.viewController(type: metricType) - presentDelegate?.present(viewController: viewController) - - stat(page: .marketOverview, event: .open(page: metricType.statPage)) - } -} - -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 deleted file mode 100644 index e552c3d6f8..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewModule.swift +++ /dev/null @@ -1,44 +0,0 @@ -enum MarketOverviewModule { - static func viewController(presentDelegate: IPresentDelegate) -> MarketOverviewViewController { - let service = MarketOverviewService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, appManager: App.shared.appManager) - - let globalService = MarketOverviewGlobalService(baseService: service) - let globalViewModel = MarketOverviewGlobalViewModel(service: globalService) - let marketOverviewDataSource = MarketOverviewGlobalDataSource(viewModel: globalViewModel, presentDelegate: presentDelegate) - - let topGainersService = MarketOverviewTopCoinsService(listType: .topGainers, baseService: service) - let topGainersDecorator = MarketListMarketFieldDecorator(service: topGainersService, statPage: .marketOverview) - let topGainersViewModel = MarketOverviewTopCoinsViewModel(service: topGainersService, decorator: topGainersDecorator) - let topGainersDataSource = MarketOverviewTopCoinsDataSource(viewModel: topGainersViewModel, presentDelegate: presentDelegate) - - let topLosersService = MarketOverviewTopCoinsService(listType: .topLosers, baseService: service) - let topLosersDecorator = MarketListMarketFieldDecorator(service: topLosersService, statPage: .marketOverview) - let topLosersViewModel = MarketOverviewTopCoinsViewModel(service: topLosersService, decorator: topLosersDecorator) - let topLosersDataSource = MarketOverviewTopCoinsDataSource(viewModel: topLosersViewModel, presentDelegate: presentDelegate) - - let topPairsService = MarketOverviewTopPairsService(baseService: service) - let topPairsDecorator = MarketListMarketPairDecorator(service: topPairsService) - let topPairsViewModel = MarketOverviewTopPairsViewModel(service: topPairsService, decorator: topPairsDecorator) - let topPairsDataSource = MarketOverviewTopPairsDataSource(viewModel: topPairsViewModel, presentDelegate: presentDelegate) - - let topPlatformsService = MarketOverviewTopPlatformsService(baseService: service) - let topPlatformsDecorator = MarketListTopPlatformDecorator(service: topPlatformsService) - let topPlatformsViewModel = MarketOverviewTopPlatformsViewModel(service: topPlatformsService, decorator: topPlatformsDecorator) - let topPlatformsDataSource = MarketOverviewTopPlatformsDataSource(viewModel: topPlatformsViewModel, presentDelegate: presentDelegate) - - let categoryService = MarketOverviewCategoryService(listType: .topGainers, baseService: service) - let categoryViewModel = MarketOverviewCategoryViewModel(service: categoryService) - let categoryDataSource = MarketOverviewCategoryDataSource(viewModel: categoryViewModel, presentDelegate: presentDelegate) - - let viewModel = MarketOverviewViewModel(service: service) - - return MarketOverviewViewController(viewModel: viewModel, dataSources: [ - marketOverviewDataSource, - topGainersDataSource, - topLosersDataSource, - topPairsDataSource, - topPlatformsDataSource, - categoryDataSource, - ]) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewService.swift deleted file mode 100644 index daaa410a5a..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewService.swift +++ /dev/null @@ -1,74 +0,0 @@ -import Combine -import Foundation -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class MarketOverviewService { - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private let appManager: IAppManager - private let disposeBag = DisposeBag() - private var cancellables = Set() - private var tasks = Set() - - @PostPublished private(set) var state: DataStatus = .loading - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, appManager: IAppManager) { - self.marketKit = marketKit - self.currencyManager = currencyManager - self.appManager = appManager - } - - private func syncState() { - tasks = Set() - - if case .failed = state { - state = .loading - } - - Task { [weak self, marketKit, currency] in - do { - let currencyCode = currency.code - - async let marketOverview = try marketKit.marketOverview(currencyCode: currencyCode) - async let topMovers = try marketKit.topMovers(currencyCode: currencyCode) - - let item = try await Item(marketOverview: marketOverview, topMovers: topMovers) - self?.state = .completed(item) - } catch { - self?.state = .failed(error) - } - }.store(in: &tasks) - } -} - -extension MarketOverviewService { - var currency: Currency { - currencyManager.baseCurrency - } - - func load() { - currencyManager.$baseCurrency - .sink { [weak self] _ in - self?.syncState() - } - .store(in: &cancellables) - - subscribe(disposeBag, appManager.willEnterForegroundObservable) { [weak self] in self?.syncState() } - - syncState() - } - - func refresh() { - syncState() - } -} - -extension MarketOverviewService { - struct Item { - let marketOverview: MarketOverview - let topMovers: TopMovers - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewController.swift deleted file mode 100644 index fd47400682..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewController.swift +++ /dev/null @@ -1,128 +0,0 @@ -import Chart -import ComponentKit -import HUD -import RxCocoa -import RxSwift -import SectionsTableView -import ThemeKit -import UIKit - -protocol IMarketOverviewDataSource { - var isReady: Bool { get } - var updateObservable: Observable { get } - func sections(tableView: SectionsTableView) -> [SectionProtocol] -} - -class MarketOverviewViewController: ThemeViewController { - private let disposeBag = DisposeBag() - - private let viewModel: MarketOverviewViewModel - private let dataSources: [IMarketOverviewDataSource] - - private let tableView = SectionsTableView(style: .grouped) - private let spinner = HUDActivityView.create(with: .medium24) - private let errorView = PlaceholderViewModule.reachabilityView() - private let refreshControl = UIRefreshControl() - - init(viewModel: MarketOverviewViewModel, dataSources: [IMarketOverviewDataSource]) { - self.viewModel = viewModel - self.dataSources = dataSources - - super.init() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - refreshControl.tintColor = .themeLeah - refreshControl.alpha = 0.6 - refreshControl.addTarget(self, action: #selector(onRefresh), for: .valueChanged) - - view.addSubview(tableView) - tableView.snp.makeConstraints { maker in - maker.edges.equalToSuperview() - } - - tableView.separatorStyle = .none - tableView.backgroundColor = .clear - tableView.showsVerticalScrollIndicator = false - - tableView.sectionDataSource = self - tableView.registerCell(forClass: MarketOverviewHeaderCell.self) - - 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.successDriver) { [weak self] in self?.sync(success: $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 - } - - for dataSource in dataSources { - subscribe(MainScheduler.instance, disposeBag, dataSource.updateObservable) { [weak self] in self?.handleDataSourceUpdate() } - } - - viewModel.onLoad() - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - tableView.refreshControl = refreshControl - } - - @objc private func onRetry() { - viewModel.refresh() - } - - @objc func onRefresh() { - viewModel.refresh() - - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in - self?.refreshControl.endRefreshing() - } - - stat(page: .marketOverview, event: .refresh) - } - - private func sync(success: Bool) { - if success { - tableView.isHidden = false - } else { - tableView.isHidden = true - } - } - - func handleDataSourceUpdate() { - 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 deleted file mode 100644 index 641a19810c..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/MarketOverviewViewModel.swift +++ /dev/null @@ -1,62 +0,0 @@ -import Combine -import RxCocoa -import RxRelay -import RxSwift - -class MarketOverviewViewModel { - private let service: MarketOverviewService - private var cancellables = Set() - - private let successRelay = BehaviorRelay(value: false) - private let loadingRelay = BehaviorRelay(value: true) - private let syncErrorRelay = BehaviorRelay(value: false) - - init(service: MarketOverviewService) { - 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) { - switch state { - case .loading: - loadingRelay.accept(true) - syncErrorRelay.accept(false) - successRelay.accept(false) - case .completed: - loadingRelay.accept(false) - syncErrorRelay.accept(false) - successRelay.accept(true) - case .failed: - loadingRelay.accept(false) - syncErrorRelay.accept(true) - successRelay.accept(false) - } - } -} - -extension MarketOverviewViewModel { - var successDriver: Driver { - successRelay.asDriver() - } - - var loadingDriver: Driver { - loadingRelay.asDriver() - } - - var syncErrorDriver: Driver { - syncErrorRelay.asDriver() - } - - func onLoad() { - service.load() - } - - func refresh() { - service.refresh() - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsDataSource.swift deleted file mode 100644 index f16a7aa3c1..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsDataSource.swift +++ /dev/null @@ -1,47 +0,0 @@ -import UIKit - -class MarketOverviewTopCoinsDataSource: BaseMarketOverviewTopListDataSource { - private let viewModel: MarketOverviewTopCoinsViewModel - - init(viewModel: MarketOverviewTopCoinsViewModel, presentDelegate: IPresentDelegate) { - self.viewModel = viewModel - - let imageName: String - let title: String - - switch viewModel.listType { - case .topGainers: - imageName = "circle_up_24" - title = "market.top.section.header.top_gainers".localized - case .topLosers: - imageName = "circle_down_24" - title = "market.top.section.header.top_losers".localized - } - - super.init( - topListViewModel: viewModel, - presentDelegate: presentDelegate, - rightSelectorMode: .selector, - imageName: imageName, - title: title - ) - } - - override func didTapSeeAll() { - let module = MarketTopModule.viewController( - marketTop: viewModel.marketTop, - sortingField: viewModel.listType.sortingField, - marketField: viewModel.listType.marketField - ) - presentDelegate?.present(viewController: module) - - stat(page: .marketOverview, section: viewModel.listType.statSection, event: .open(page: .topCoins)) - } - - override func onSelect(listViewItem: MarketModule.ListViewItem) { - if let coinUid = listViewItem.uid, let module = CoinPageModule.viewController(coinUid: coinUid) { - presentDelegate?.present(viewController: module) - stat(page: .marketOverview, section: viewModel.listType.statSection, event: .openCoin(coinUid: coinUid)) - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsService.swift deleted file mode 100644 index e513a8bf98..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsService.swift +++ /dev/null @@ -1,104 +0,0 @@ -import Combine -import Foundation -import MarketKit -import RxRelay -import RxSwift - -class MarketOverviewTopCoinsService { - private let baseService: MarketOverviewService - private var cancellables = Set() - - private(set) var marketTop: MarketModule.MarketTop = .top100 - let listType: ListType - - private let marketInfosRelay = PublishRelay<[MarketInfo]?>() - private(set) var marketInfos: [MarketInfo]? { - didSet { - marketInfosRelay.accept(marketInfos) - } - } - - init(listType: ListType, baseService: MarketOverviewService) { - self.listType = listType - self.baseService = baseService - - baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - sync(state: baseService.state) - } - - private func sync(state: DataStatus) { - marketInfos = state.data.map { item in - switch listType { - case .topGainers: - switch marketTop { - case .top100: return item.topMovers.gainers100 - case .top200: return item.topMovers.gainers200 - case .top300: return item.topMovers.gainers300 - } - case .topLosers: - switch marketTop { - case .top100: return item.topMovers.losers100 - case .top200: return item.topMovers.losers200 - case .top300: return item.topMovers.losers300 - } - } - } - } -} - -extension MarketOverviewTopCoinsService { - var marketInfosObservable: Observable<[MarketInfo]?> { - marketInfosRelay.asObservable() - } - - func set(marketTop: MarketModule.MarketTop) { - self.marketTop = marketTop - sync(state: baseService.state) - } -} - -extension MarketOverviewTopCoinsService: IMarketListDecoratorService { - var initialIndex: Int { - 0 - } - - var currency: Currency { - baseService.currency - } - - var priceChangeType: MarketModule.PriceChangeType { - .day - } - - func onUpdate(index _: Int) {} -} - -extension MarketOverviewTopCoinsService { - enum ListType: String, CaseIterable { - case topGainers - case topLosers - - var sortingField: MarketModule.SortingField { - switch self { - case .topGainers: return .topGainers - case .topLosers: return .topLosers - } - } - - var marketField: MarketModule.MarketField { - switch self { - case .topGainers, .topLosers: return .price - } - } - - var statSection: StatSection { - switch self { - case .topGainers: return .topGainers - case .topLosers: return .topLosers - } - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsViewModel.swift deleted file mode 100644 index 110ff412e4..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopCoins/MarketOverviewTopCoinsViewModel.swift +++ /dev/null @@ -1,56 +0,0 @@ -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -class MarketOverviewTopCoinsViewModel { - private let service: MarketOverviewTopCoinsService - private let decorator: MarketListMarketFieldDecorator - private let disposeBag = DisposeBag() - - private let listViewItemsRelay = BehaviorRelay<[MarketModule.ListViewItem]?>(value: nil) - - init(service: MarketOverviewTopCoinsService, decorator: MarketListMarketFieldDecorator) { - self.service = service - self.decorator = decorator - - subscribe(disposeBag, service.marketInfosObservable) { [weak self] in self?.sync(marketInfos: $0) } - - sync(marketInfos: service.marketInfos) - } - - private func sync(marketInfos: [MarketInfo]?) { - listViewItemsRelay.accept(marketInfos.map { $0.map { decorator.listViewItem(item: $0) } }) - } -} - -extension MarketOverviewTopCoinsViewModel { - var marketTop: MarketModule.MarketTop { - service.marketTop - } - - var listType: MarketOverviewTopCoinsService.ListType { - service.listType - } -} - -extension MarketOverviewTopCoinsViewModel: IBaseMarketOverviewTopListViewModel { - var listViewItemsDriver: Driver<[MarketModule.ListViewItem]?> { - listViewItemsRelay.asDriver() - } - - var selectorTitles: [String] { - MarketModule.MarketTop.allCases.map(\.title) - } - - var selectorIndex: Int { - MarketModule.MarketTop.allCases.firstIndex(of: service.marketTop) ?? 0 - } - - func onSelect(selectorIndex: Int) { - let marketTop = MarketModule.MarketTop.allCases[selectorIndex] - service.set(marketTop: marketTop) - - stat(page: .marketOverview, section: listType.statSection, event: .switchMarketTop(marketTop: marketTop.statMarketTop)) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsDataSource.swift deleted file mode 100644 index 693ffd39a9..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsDataSource.swift +++ /dev/null @@ -1,34 +0,0 @@ -import UIKit - -class MarketOverviewTopPairsDataSource: BaseMarketOverviewTopListDataSource { - private let viewModel: MarketOverviewTopPairsViewModel - - init(viewModel: MarketOverviewTopPairsViewModel, presentDelegate: IPresentDelegate) { - self.viewModel = viewModel - - super.init( - topListViewModel: viewModel, - presentDelegate: presentDelegate, - rightSelectorMode: .none, - imageName: "pairs_24", - title: "market.top.top_market_pairs".localized - ) - } - - override func didTapSeeAll() { - let module = MarketTopPairsModule.viewController() - presentDelegate?.present(viewController: module) - - stat(page: .marketOverview, event: .open(page: .topMarketPairs)) - } - - override func onSelect(listViewItem: MarketModule.ListViewItem) { - guard let uid = listViewItem.uid, let marketPair = viewModel.marketPair(uid: uid), let tradeUrl = marketPair.tradeUrl else { - return - } - - UrlManager.open(url: tradeUrl) - - stat(page: .marketOverview, event: .open(page: .externalMarketPair)) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsService.swift deleted file mode 100644 index 1385522789..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsService.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Combine -import Foundation -import HsExtensions -import MarketKit - -class MarketOverviewTopPairsService { - private let baseService: MarketOverviewService - private var cancellables = Set() - - @PostPublished private(set) var marketPairs: [MarketPair]? - - init(baseService: MarketOverviewService) { - self.baseService = baseService - - baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - sync(state: baseService.state) - } - - private func sync(state: DataStatus) { - marketPairs = state.data.map { item in - item.marketOverview.topPairs - } - } -} - -extension MarketOverviewTopPairsService: IMarketListMarketPairDecoratorService { - var currency: Currency { - baseService.currency - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsViewModel.swift deleted file mode 100644 index 7fbcec2f7c..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPairs/MarketOverviewTopPairsViewModel.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Combine -import Foundation -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -class MarketOverviewTopPairsViewModel { - private let service: MarketOverviewTopPairsService - private let decorator: MarketListMarketPairDecorator - private var cancellables = Set() - - private let listViewItemsRelay = BehaviorRelay<[MarketModule.ListViewItem]?>(value: nil) - - init(service: MarketOverviewTopPairsService, decorator: MarketListMarketPairDecorator) { - self.service = service - self.decorator = decorator - - service.$marketPairs - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.sync(marketPairs: $0) } - .store(in: &cancellables) - - sync(marketPairs: service.marketPairs) - } - - private func sync(marketPairs: [MarketPair]?) { - listViewItemsRelay.accept(marketPairs.map { $0.map { decorator.listViewItem(item: $0) } }) - } -} - -extension MarketOverviewTopPairsViewModel { - func marketPair(uid: String) -> MarketPair? { - service.marketPairs?.first { $0.uid == uid } - } -} - -extension MarketOverviewTopPairsViewModel: IBaseMarketOverviewTopListViewModel { - var listViewItemsDriver: Driver<[MarketModule.ListViewItem]?> { - listViewItemsRelay.asDriver() - } - - var selectorTitles: [String] { - [] - } - - var selectorIndex: Int { - 0 - } - - func onSelect(selectorIndex _: Int) {} -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsDataSource.swift deleted file mode 100644 index 24458fc006..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsDataSource.swift +++ /dev/null @@ -1,34 +0,0 @@ -import UIKit - -class MarketOverviewTopPlatformsDataSource: BaseMarketOverviewTopListDataSource { - private let viewModel: MarketOverviewTopPlatformsViewModel - - init(viewModel: MarketOverviewTopPlatformsViewModel, presentDelegate: IPresentDelegate) { - self.viewModel = viewModel - - super.init( - topListViewModel: viewModel, - presentDelegate: presentDelegate, - rightSelectorMode: .selector, - imageName: "blocks_24", - title: "market.top.top_platforms".localized - ) - } - - override func didTapSeeAll() { - let module = MarketTopPlatformsModule.viewController(timePeriod: viewModel.timePeriod) - presentDelegate?.present(viewController: module) - - stat(page: .marketOverview, event: .open(page: .topPlatforms)) - } - - override func onSelect(listViewItem: MarketModule.ListViewItem) { - guard let uid = listViewItem.uid, let topPlatform = viewModel.topPlatform(uid: uid) else { - return - } - - presentDelegate?.present(viewController: TopPlatformModule.viewController(topPlatform: topPlatform)) - - stat(page: .marketOverview, event: .openPlatform(chainUid: uid)) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsService.swift deleted file mode 100644 index e39d36df96..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsService.swift +++ /dev/null @@ -1,53 +0,0 @@ -import Combine -import Foundation -import MarketKit -import RxRelay -import RxSwift - -class MarketOverviewTopPlatformsService { - private let baseService: MarketOverviewService - private var cancellables = Set() - - var timePeriod: HsTimePeriod = .week1 { - didSet { - sync() - } - } - - private let topPlatformsRelay = PublishRelay<[TopPlatform]?>() - private(set) var topPlatforms: [TopPlatform]? { - didSet { - topPlatformsRelay.accept(topPlatforms) - } - } - - init(baseService: MarketOverviewService) { - self.baseService = baseService - - baseService.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - sync() - } - - private func sync(state: DataStatus? = nil) { - let state = state ?? baseService.state - - topPlatforms = state.data.map { item in - item.marketOverview.topPlatforms - } - } -} - -extension MarketOverviewTopPlatformsService { - var topPlatformsObservable: Observable<[TopPlatform]?> { - topPlatformsRelay.asObservable() - } -} - -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 deleted file mode 100644 index cad06e0059..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketOverview/TopPlatforms/MarketOverviewTopPlatformsViewModel.swift +++ /dev/null @@ -1,56 +0,0 @@ -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -class MarketOverviewTopPlatformsViewModel { - private let service: MarketOverviewTopPlatformsService - private let decorator: MarketListTopPlatformDecorator - private let disposeBag = DisposeBag() - - private let listViewItemsRelay = BehaviorRelay<[MarketModule.ListViewItem]?>(value: nil) - - init(service: MarketOverviewTopPlatformsService, decorator: MarketListTopPlatformDecorator) { - self.service = service - self.decorator = decorator - - subscribe(disposeBag, service.topPlatformsObservable) { [weak self] in self?.sync(topPlatforms: $0) } - - sync(topPlatforms: service.topPlatforms) - } - - private func sync(topPlatforms: [TopPlatform]?) { - listViewItemsRelay.accept(topPlatforms.map { $0.map { decorator.listViewItem(item: $0) } }) - } -} - -extension MarketOverviewTopPlatformsViewModel { - var timePeriod: HsTimePeriod { - service.timePeriod - } - - 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(\.shortTitle) - } - - var selectorIndex: Int { - MarketTopPlatformsModule.selectorValues.firstIndex(of: service.timePeriod) ?? 0 - } - - func onSelect(selectorIndex: Int) { - let timePeriod = MarketTopPlatformsModule.selectorValues[selectorIndex] - service.timePeriod = timePeriod - - stat(page: .marketOverview, section: .topPlatforms, event: .switchPeriod(period: timePeriod.statPeriod)) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostModule.swift deleted file mode 100644 index f13db300bf..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostModule.swift +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index c68b62618f..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostService.swift +++ /dev/null @@ -1,59 +0,0 @@ -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class MarketPostService { - private let marketKit: Kit - private var tasks = Set() - - private let stateRelay = PublishRelay() - private(set) var state: State = .loading { - didSet { - stateRelay.accept(state) - } - } - - init(marketKit: Kit) { - self.marketKit = marketKit - } - - private func fetch() { - tasks = Set() - - if case .failed = state { - state = .loading - } - - Task { [weak self, marketKit] in - do { - let posts = try await marketKit.posts() - self?.state = .loaded(posts: posts) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } -} - -extension MarketPostService { - var stateObservable: Observable { - stateRelay.asObservable() - } - - func load() { - fetch() - } - - 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 deleted file mode 100644 index 2cb8acadc1..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewController.swift +++ /dev/null @@ -1,159 +0,0 @@ -import ComponentKit -import HUD -import RxSwift -import SectionsTableView -import ThemeKit -import UIKit - -class MarketPostViewController: ThemeViewController { - private let viewModel: MarketPostViewModel - 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 let refreshControl = UIRefreshControl() - - weak var parentNavigationController: UINavigationController? - - private var viewItems: [MarketPostViewModel.ViewItem]? - - init(viewModel: MarketPostViewModel, 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() - - refreshControl.tintColor = .themeLeah - refreshControl.alpha = 0.6 - refreshControl.addTarget(self, action: #selector(onRefresh), for: .valueChanged) - - view.addSubview(tableView) - tableView.snp.makeConstraints { maker in - maker.edges.equalToSuperview() - } - - tableView.separatorStyle = .none - tableView.backgroundColor = .clear - - tableView.sectionDataSource = self - tableView.registerCell(forClass: PostCell.self) - - 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 - } - - viewModel.onLoad() - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - tableView.refreshControl = refreshControl - } - - @objc private func onRetry() { - refresh() - } - - @objc private func onRefresh() { - refresh() - - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in - self?.refreshControl.endRefreshing() - } - - stat(page: .news, event: .refresh) - } - - private func refresh() { - viewModel.refresh() - } - - private func sync(viewItems: [MarketPostViewModel.ViewItem]?) { - self.viewItems = viewItems - - if viewItems != nil { - tableView.bounces = true - } else { - tableView.bounces = false - } - - tableView.reload() - } - - private func open(url: String) { - urlManager.open(url: url, from: parentNavigationController) - - stat(page: .news, event: .open(page: .externalNews)) - } -} - -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) - } - ) - } - - func buildSections() -> [SectionProtocol] { - var sections = [SectionProtocol]() - - 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)] - ) - - sections.append(section) - } - } - - return sections - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewModel.swift deleted file mode 100644 index d93cf1a948..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketPosts/MarketPostViewModel.swift +++ /dev/null @@ -1,100 +0,0 @@ -import Foundation -import MarketKit -import RxCocoa -import RxRelay -import RxSwift - -class MarketPostViewModel { - private let service: MarketPostService - private let disposeBag = DisposeBag() - - private let viewItemsRelay = BehaviorRelay<[ViewItem]?>(value: nil) - private let loadingRelay = BehaviorRelay(value: false) - private let syncErrorRelay = BehaviorRelay(value: false) - - init(service: MarketPostService) { - self.service = service - - subscribe(disposeBag, service.stateObservable) { [weak self] in self?.sync(state: $0) } - - sync(state: service.state) - } - - private func sync(state: MarketPostService.State) { - switch state { - case .loading: - viewItemsRelay.accept(nil) - loadingRelay.accept(true) - syncErrorRelay.accept(false) - case let .loaded(posts): - viewItemsRelay.accept(posts.map { viewItem(post: $0) }) - loadingRelay.accept(false) - syncErrorRelay.accept(false) - case .failed: - viewItemsRelay.accept(nil) - loadingRelay.accept(false) - syncErrorRelay.accept(true) - } - } - - 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 - ) - } - - private func timeAgo(interval: TimeInterval) -> String { - var interval = Int(interval) / 60 - - // interval from post in minutes - if interval < 60 { - return "timestamp.min_ago".localized(max(1, interval)) - } - - // interval in hours - interval /= 60 - if interval < 24 { - return "timestamp.hours_ago".localized(interval) - } - - // interval in days - interval /= 24 - return "timestamp.days_ago".localized(interval) - } -} - -extension MarketPostViewModel { - var viewItemsDriver: Driver<[ViewItem]?> { - viewItemsRelay.asDriver() - } - - var loadingDriver: Driver { - loadingRelay.asDriver() - } - - var syncErrorDriver: Driver { - syncErrorRelay.asDriver() - } - - func onLoad() { - service.load() - } - - func refresh() { - service.refresh() - } -} - -extension MarketPostViewModel { - struct ViewItem { - let source: String - let title: String - let body: String - let timeAgo: String - let url: String - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopModule.swift deleted file mode 100644 index c747a0b17a..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopModule.swift +++ /dev/null @@ -1,27 +0,0 @@ -import ThemeKit -import UIKit - -enum MarketTopModule { - static func viewController(marketTop: MarketModule.MarketTop = .top100, sortingField: MarketModule.SortingField = .highestCap, marketField: MarketModule.MarketField = .price) -> UIViewController { - let service = MarketTopService( - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - marketTop: marketTop, - sortingField: sortingField, - marketField: marketField - ) - let watchlistToggleService = MarketWatchlistToggleService( - coinUidService: service, - watchlistManager: App.shared.watchlistManager, - statPage: .topCoins - ) - - let decorator = MarketListMarketFieldDecorator(service: service, statPage: .topCoins) - let listViewModel = MarketListWatchViewModel(service: service, watchlistToggleService: watchlistToggleService, decorator: decorator) - let headerViewModel = MarketMultiSortHeaderViewModel(service: service, decorator: decorator) - - let viewController = MarketTopViewController(listViewModel: listViewModel, headerViewModel: headerViewModel) - - return ThemeNavigationController(rootViewController: viewController) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopService.swift deleted file mode 100644 index 86ab164a84..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopService.swift +++ /dev/null @@ -1,131 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class MarketTopService: IMarketMultiSortHeaderService { - typealias Item = MarketInfo - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private let disposeBag = DisposeBag() - private var tasks = Set() - - private var internalState: State = .loading { - didSet { - syncState() - } - } - - @PostPublished private(set) var state: MarketListServiceState = .loading - - var marketTop: MarketModule.MarketTop { - didSet { - syncIfPossible() - - stat(page: .topCoins, event: .switchMarketTop(marketTop: marketTop.statMarketTop)) - } - } - - var sortingField: MarketModule.SortingField { - didSet { - syncIfPossible() - - stat(page: .topCoins, event: .switchSortType(sortType: sortingField.statSortType)) - } - } - - let initialIndex: Int - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, marketTop: MarketModule.MarketTop, sortingField: MarketModule.SortingField, marketField: MarketModule.MarketField) { - self.marketKit = marketKit - self.currencyManager = currencyManager - self.marketTop = marketTop - self.sortingField = sortingField - initialIndex = marketField.rawValue - - syncMarketInfos() - } - - private func syncMarketInfos() { - tasks = Set() - - if case .failed = state { - internalState = .loading - } - - Task { [weak self, marketKit, currency] in - do { - let marketInfos = try await marketKit.marketInfos(top: 1000, currencyCode: currency.code) - self?.internalState = .loaded(marketInfos: marketInfos) - } catch { - self?.internalState = .failed(error: error) - } - }.store(in: &tasks) - } - - private func syncState(reorder: Bool = false) { - switch internalState { - case .loading: - state = .loading - case let .loaded(marketInfos): - let marketInfos: [MarketInfo] = Array(marketInfos.prefix(marketTop.rawValue)) - state = .loaded(items: marketInfos.sorted(sortingField: sortingField, priceChangeType: priceChangeType), softUpdate: false, reorder: reorder) - case let .failed(error): - state = .failed(error: error) - } - } - - private func syncIfPossible() { - guard case .loaded = internalState else { - return - } - - syncState(reorder: true) - } -} - -extension MarketTopService: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func refresh() { - syncMarketInfos() - } -} - -extension MarketTopService: IMarketListCoinUidService { - func coinUid(index: Int) -> String? { - guard case let .loaded(marketInfos, _, _) = state, index < marketInfos.count else { - return nil - } - - return marketInfos[index].fullCoin.coin.uid - } -} - -extension MarketTopService: IMarketListDecoratorService { - var currency: Currency { - currencyManager.baseCurrency - } - - var priceChangeType: MarketModule.PriceChangeType { - .day - } - - func onUpdate(index _: Int) { - if case let .loaded(marketInfos, _, _) = state { - state = .loaded(items: marketInfos, softUpdate: false, reorder: false) - } - } -} - -extension MarketTopService { - private enum State { - case loading - case loaded(marketInfos: [MarketInfo]) - case failed(error: Error) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopViewController.swift deleted file mode 100644 index 1d11e99751..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTop/MarketTopViewController.swift +++ /dev/null @@ -1,59 +0,0 @@ -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketTopViewController: MarketListViewController { - private let multiSortHeaderView: MarketMultiSortHeaderView - - override var viewController: UIViewController? { self } - override var headerView: UITableViewHeaderFooterView? { multiSortHeaderView } - override var refreshEnabled: Bool { false } - - init(listViewModel: IMarketListViewModel, headerViewModel: MarketMultiSortHeaderViewModel) { - multiSortHeaderView = MarketMultiSortHeaderView(viewModel: headerViewModel, hasLeftSelector: true) - - super.init(listViewModel: listViewModel, statPage: .topCoins) - - multiSortHeaderView.viewController = self - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: MarketHeaderCell.self) - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded _: Bool) -> [SectionProtocol] { - [ - Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { cell, _ in - cell.set( - title: "market.top.title".localized, - description: "market.top.description".localized, - imageMode: .remote(imageUrl: "top_coins".headerImageUrl) - ) - } - ), - ] - ), - ] - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketListMarketPairDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketListMarketPairDecorator.swift deleted file mode 100644 index 9f009695cc..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketListMarketPairDecorator.swift +++ /dev/null @@ -1,38 +0,0 @@ -import Foundation -import MarketKit - -protocol IMarketListMarketPairDecoratorService { - var currency: Currency { get } -} - -class MarketListMarketPairDecorator { - typealias Item = MarketPair - - private let service: IMarketListMarketPairDecoratorService - - init(service: IMarketListMarketPairDecoratorService) { - self.service = service - } -} - -extension MarketListMarketPairDecorator: IMarketListDecorator { - func listViewItem(item: MarketPair) -> MarketModule.ListViewItem { - let currency = service.currency - - let volume = item.volume.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized - let price = item.price.flatMap { ValueFormatter.instance.formatShort(value: $0, decimalCount: 8, symbol: item.target) } ?? "n/a".localized - - return MarketModule.ListViewItem( - uid: item.uid, - iconUrl: item.marketImageUrl, - iconShape: .square, - iconPlaceholderName: "placeholder_rectangle_32", - leftPrimaryValue: "\(item.base)/\(item.target)", - leftSecondaryValue: item.marketName, - badge: "\(item.rank)", - badgeSecondaryValue: nil, - rightPrimaryValue: volume, - rightSecondaryValue: .volume(price) - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsModule.swift deleted file mode 100644 index 3e1f4f2f97..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsModule.swift +++ /dev/null @@ -1,13 +0,0 @@ -import ThemeKit -import UIKit - -enum MarketTopPairsModule { - static func viewController() -> UIViewController { - let viewModel = MarketTopPairsViewModel(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, appManager: App.shared.appManager) - let decorator = MarketListMarketPairDecorator(service: viewModel) - let listViewModel = MarketListViewModel(service: viewModel, decorator: decorator) - let viewController = MarketTopPairsViewController(viewModel: viewModel, listViewModel: listViewModel) - - return ThemeNavigationController(rootViewController: viewController) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsViewController.swift deleted file mode 100644 index 623bdec915..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsViewController.swift +++ /dev/null @@ -1,66 +0,0 @@ -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketTopPairsViewController: MarketListViewController { - private let viewModel: MarketTopPairsViewModel - - override var viewController: UIViewController? { self } - override var refreshEnabled: Bool { false } - - init(viewModel: MarketTopPairsViewModel, listViewModel: IMarketListViewModel) { - self.viewModel = viewModel - - super.init(listViewModel: listViewModel, statPage: .topMarketPairs) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: MarketHeaderCell.self) - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded _: Bool) -> [SectionProtocol] { - [ - Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { cell, _ in - cell.set( - title: "top_pairs.title".localized, - description: "top_pairs.description".localized, - imageMode: .remote(imageUrl: "token_pairs".headerImageUrl) - ) - } - ), - ] - ), - ] - } - - override func onSelect(viewItem: MarketModule.ListViewItem) { - guard let uid = viewItem.uid, let marketPair = viewModel.marketPair(uid: uid), let tradeUrl = marketPair.tradeUrl else { - return - } - - UrlManager.open(url: tradeUrl) - - stat(page: .topMarketPairs, event: .open(page: .externalMarketPair)) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsViewModel.swift deleted file mode 100644 index 4dc89c76ca..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPairs/MarketTopPairsViewModel.swift +++ /dev/null @@ -1,72 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxSwift - -class MarketTopPairsViewModel { - typealias Item = MarketPair - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private var disposeBag = DisposeBag() - private var cancellables = Set() - private var tasks = Set() - - @PostPublished private(set) var state: MarketListServiceState = .loading - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, appManager: IAppManager) { - self.marketKit = marketKit - self.currencyManager = currencyManager - - currencyManager.$baseCurrency - .sink { [weak self] _ in - self?.sync() - } - .store(in: &cancellables) - - subscribe(disposeBag, appManager.willEnterForegroundObservable) { [weak self] in self?.sync() } - - sync() - } - - private func sync() { - tasks = Set() - - if case .failed = state { - state = .loading - } - - Task { [weak self, marketKit, currency] in - do { - let topPairs = try await marketKit.topPairs(currencyCode: currency.code) - self?.state = .loaded(items: topPairs, softUpdate: false, reorder: false) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } - - func marketPair(uid: String) -> MarketPair? { - guard case let .loaded(data, _, _) = state else { - return nil - } - - return data.first { $0.uid == uid } - } -} - -extension MarketTopPairsViewModel: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func refresh() { - sync() - } -} - -extension MarketTopPairsViewModel: IMarketListMarketPairDecoratorService { - var currency: Currency { - currencyManager.baseCurrency - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketListTopPlatformDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketListTopPlatformDecorator.swift deleted file mode 100644 index 95cc9cc9a7..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketListTopPlatformDecorator.swift +++ /dev/null @@ -1,53 +0,0 @@ -import ComponentKit -import Foundation -import MarketKit - -protocol IMarketListTopPlatformDecoratorService { - var currency: Currency { get } - var timePeriod: HsTimePeriod { get } -} - -class MarketListTopPlatformDecorator { - typealias Item = MarketKit.TopPlatform - - private let service: IMarketListTopPlatformDecoratorService - - init(service: IMarketListTopPlatformDecoratorService) { - self.service = service - } -} - -extension MarketListTopPlatformDecorator: IMarketListDecorator { - func listViewItem(item: MarketKit.TopPlatform) -> MarketModule.ListViewItem { - let currency = service.currency - - let protocols = item.protocolsCount.map { "market.top.protocols".localized(String($0)) } ?? "" - - let marketCap = item.marketCap.flatMap { ValueFormatter.instance.formatShort(currency: currency, value: $0) } ?? "n/a".localized - - let rank = item.rank - let rankDiff: Int? = rank.flatMap { rank in - item.ranks[service.timePeriod].flatMap { pastRank in - let diff = pastRank - rank - return diff == 0 ? nil : diff - } - } - let rankChange: BadgeView.Change? = rankDiff.map { $0 < 0 ? .down("\(abs($0))") : .up("\($0)") } - - let diff = item.changes[service.timePeriod] - 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 - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsModule.swift deleted file mode 100644 index 0b2988b41d..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsModule.swift +++ /dev/null @@ -1,75 +0,0 @@ -import MarketKit -import ThemeKit -import UIKit - -enum MarketTopPlatformsModule { - static func viewController(timePeriod: HsTimePeriod) -> UIViewController { - let service = MarketTopPlatformsService(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, appManager: App.shared.appManager, timePeriod: timePeriod) - - let decorator = MarketListTopPlatformDecorator(service: service) - let viewModel = MarketTopPlatformsViewModel(service: service) - let listViewModel = MarketListViewModel(service: service, decorator: decorator) - let headerViewModel = TopPlatformsMultiSortHeaderViewModel(service: service, decorator: decorator) - - let viewController = MarketTopPlatformsViewController(viewModel: viewModel, listViewModel: listViewModel, headerViewModel: headerViewModel) - - return ThemeNavigationController(rootViewController: viewController) - } - - enum SortType: Int, CaseIterable { - case highestCap - case lowestCap - case topGainers - case topLosers - - var title: String { - switch self { - case .highestCap: return "market.top.highest_cap".localized - case .lowestCap: return "market.top.lowest_cap".localized - case .topGainers: return "market.top.top_gainers".localized - case .topLosers: return "market.top.top_losers".localized - } - } - } - - static var selectorValues: [HsTimePeriod] { - [ - HsTimePeriod.week1, - HsTimePeriod.month1, - HsTimePeriod.month3, - ] - } -} - -extension [MarketKit.TopPlatform] { - func sorted(sortType: MarketTopPlatformsModule.SortType, timePeriod: HsTimePeriod) -> [TopPlatform] { - sorted { lhsPlatform, rhsPlatform in - let lhsCap = lhsPlatform.marketCap - let rhsCap = rhsPlatform.marketCap - - let lhsChange = lhsPlatform.changes[timePeriod] - let rhsChange = rhsPlatform.changes[timePeriod] - - switch sortType { - case .highestCap, .lowestCap: - guard let lhsCap else { - return true - } - guard let rhsCap else { - return false - } - - return sortType == .highestCap ? lhsCap > rhsCap : lhsCap < rhsCap - case .topGainers, .topLosers: - guard let lhsChange else { - return true - } - guard let rhsChange else { - return false - } - - return sortType == .topGainers ? lhsChange > rhsChange : lhsChange < rhsChange - } - } - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsService.swift deleted file mode 100644 index 0412f9d13b..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsService.swift +++ /dev/null @@ -1,111 +0,0 @@ -import Combine -import Foundation -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class MarketTopPlatformsService { - typealias Item = TopPlatform - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private var disposeBag = DisposeBag() - private var cancellables = Set() - private var tasks = Set() - - var sortType: MarketTopPlatformsModule.SortType = .highestCap { - didSet { - syncIfPossible() - - stat(page: .topPlatforms, event: .switchSortType(sortType: sortType.statSortType)) - } - } - - var timePeriod: MarketKit.HsTimePeriod { - didSet { - syncIfPossible() - - stat(page: .topPlatforms, event: .switchPeriod(period: timePeriod.statPeriod)) - } - } - - private var internalState: MarketListServiceState = .loading - - @PostPublished private(set) var state: MarketListServiceState = .loading - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, appManager: IAppManager, timePeriod: HsTimePeriod) { - self.marketKit = marketKit - self.currencyManager = currencyManager - self.timePeriod = timePeriod - - currencyManager.$baseCurrency - .sink { [weak self] _ in - self?.sync() - } - .store(in: &cancellables) - - subscribe(disposeBag, appManager.willEnterForegroundObservable) { [weak self] in self?.sync() } - - sync() - } - - private func sync() { - tasks = Set() - - if case .failed = state { - internalState = .loading - } - - Task { [weak self, marketKit, currency] in - do { - let topPlatforms = try await marketKit.topPlatforms(currencyCode: currency.code) - self?.internalState = .loaded(items: topPlatforms, softUpdate: false, reorder: false) - self?.sync(topPlatforms: topPlatforms) - } catch { - self?.internalState = .failed(error: error) - } - }.store(in: &tasks) - } - - private func sync(topPlatforms: [TopPlatform], reorder: Bool = false) { - let sortType = sortType - let timePeriod = timePeriod - - state = .loaded(items: topPlatforms.sorted(sortType: sortType, timePeriod: timePeriod), softUpdate: false, reorder: reorder) - } - - private func syncIfPossible() { - 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 - } - - return nil - } -} - -extension MarketTopPlatformsService: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func refresh() { - sync() - } -} - -extension MarketTopPlatformsService: IMarketListTopPlatformDecoratorService { - var currency: Currency { - currencyManager.baseCurrency - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewController.swift deleted file mode 100644 index 70bd616cf4..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewController.swift +++ /dev/null @@ -1,71 +0,0 @@ -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketTopPlatformsViewController: MarketListViewController { - private let viewModel: MarketTopPlatformsViewModel - private let multiSortHeaderView: MarketMultiSortHeaderView - - override var viewController: UIViewController? { self } - override var headerView: UITableViewHeaderFooterView? { multiSortHeaderView } - override var refreshEnabled: Bool { false } - - init(viewModel: MarketTopPlatformsViewModel, listViewModel: IMarketListViewModel, headerViewModel: TopPlatformsMultiSortHeaderViewModel) { - self.viewModel = viewModel - multiSortHeaderView = MarketMultiSortHeaderView(viewModel: headerViewModel) - - super.init(listViewModel: listViewModel, statPage: .topPlatforms) - - multiSortHeaderView.viewController = self - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: MarketHeaderCell.self) - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded _: Bool) -> [SectionProtocol] { - [ - Section( - id: "header", - rows: [ - Row( - id: "header", - height: MarketHeaderCell.height, - bind: { cell, _ in - cell.set( - title: "top_platforms.title".localized, - description: "top_platforms.description".localized, - imageMode: .remote(imageUrl: "top_platforms".headerImageUrl) - ) - } - ), - ] - ), - ] - } - - override func onSelect(viewItem: MarketModule.ListViewItem) { - guard let uid = viewItem.uid, let topPlatform = viewModel.topPlatform(uid: uid) else { - return - } - - present(TopPlatformModule.viewController(topPlatform: topPlatform), animated: true) - - stat(page: .topPlatforms, event: .openPlatform(chainUid: uid)) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewModel.swift deleted file mode 100644 index a162b9f5ff..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/MarketTopPlatformsViewModel.swift +++ /dev/null @@ -1,13 +0,0 @@ -import MarketKit - -class MarketTopPlatformsViewModel { - let service: MarketTopPlatformsService - - init(service: MarketTopPlatformsService) { - self.service = service - } - - 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 deleted file mode 100644 index 86b3c5cecf..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTopPlatforms/TopPlatformsMultiSortHeaderViewModel.swift +++ /dev/null @@ -1,47 +0,0 @@ -import MarketKit - -class TopPlatformsMultiSortHeaderViewModel { - private let service: MarketTopPlatformsService - private let decorator: MarketListTopPlatformDecorator - - init(service: MarketTopPlatformsService, decorator: MarketListTopPlatformDecorator) { - self.service = service - self.decorator = decorator - } -} - -extension TopPlatformsMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel { - var sortItems: [String] { - MarketTopPlatformsModule.SortType.allCases.map(\.title) - } - - var sortIndex: Int { - MarketTopPlatformsModule.SortType.allCases.firstIndex(of: service.sortType) ?? 0 - } - - var leftSelectorItems: [String] { - [] - } - - var leftSelectorIndex: Int { - 0 - } - - var rightSelectorItems: [String] { - MarketTopPlatformsModule.selectorValues.map(\.shortTitle) - } - - var rightSelectorIndex: Int { - MarketTopPlatformsModule.selectorValues.firstIndex(of: service.timePeriod) ?? 0 - } - - func onSelectSort(index: Int) { - service.sortType = MarketTopPlatformsModule.SortType.allCases[index] - } - - 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 deleted file mode 100644 index b6aa63dc28..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewController.swift +++ /dev/null @@ -1,331 +0,0 @@ -import Combine -import ComponentKit -import MarketKit -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketViewController: ThemeSearchViewController { - private let viewModel = MarketViewModel() - private var cancellables = Set() - - private let tabsView = FilterView(buttonStyle: .tab) - private let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal) - - private var marketOverviewViewController: MarketOverviewViewController? - private let postViewController: MarketPostViewController - private let watchlistViewController: MarketWatchlistViewController - - private let tableView = SectionsTableView(style: .plain) - private let notFoundPlaceholder = PlaceholderView(layoutType: .keyboard) - - private var state: MarketViewModel.State = .idle - - init() { - postViewController = MarketPostModule.viewController() - watchlistViewController = MarketWatchlistModule.viewController() - - super.init(scrollViews: [tableView], automaticallyShowsCancelButton: true) - - marketOverviewViewController = MarketOverviewModule.viewController(presentDelegate: self) - - tabBarItem = UITabBarItem(title: "market.tab_bar_item".localized, image: UIImage(named: "market_2_24"), tag: 0) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - title = "market.title".localized - navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "manage_2_24"), style: .plain, target: self, action: #selector(onTapFilter)) - - view.addSubview(tabsView) - tabsView.snp.makeConstraints { maker in - maker.top.equalTo(view.safeAreaLayoutGuide) - maker.leading.trailing.equalToSuperview() - maker.height.equalTo(FilterView.height) - } - - view.addSubview(pageViewController.view) - pageViewController.view.snp.makeConstraints { maker in - maker.top.equalTo(tabsView.snp.bottom) - maker.leading.trailing.equalToSuperview() - maker.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) - } - - tabsView.reload(filters: MarketModule.TabOld.allCases.map { - FilterView.ViewItem.item(title: $0.title) - }) - - tabsView.onSelect = { [weak self] index in - self?.onSelectTab(index: index) - } - - postViewController.parentNavigationController = navigationController - watchlistViewController.parentNavigationController = navigationController - - view.addSubview(tableView) - tableView.snp.makeConstraints { maker in - maker.leading.top.trailing.equalToSuperview() - maker.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) - } - - tableView.sectionDataSource = self - tableView.registerHeaderFooter(forClass: TransactionDateHeaderView.self) - - tableView.sectionHeaderTopPadding = 0 - tableView.backgroundColor = .themeTyler - tableView.separatorStyle = .none - - view.addSubview(notFoundPlaceholder) - notFoundPlaceholder.snp.makeConstraints { maker in - maker.edges.equalTo(view.safeAreaLayoutGuide) - } - - notFoundPlaceholder.image = UIImage(named: "not_found_48") - notFoundPlaceholder.text = "market_discovery.not_found".localized - - viewModel.$currentTab - .sink { [weak self] currentTab in - self?.tabsView.select(index: MarketModule.TabOld.allCases.firstIndex(of: currentTab) ?? 0) - self?.setViewPager(tab: currentTab) - } - .store(in: &cancellables) - - viewModel.$state - .sink { [weak self] in self?.sync(state: $0) } - .store(in: &cancellables) - - viewModel.favoritedPublisher - .sink { HudHelper.instance.show(banner: .addedToWatchlist) } - .store(in: &cancellables) - - viewModel.unfavoritedPublisher - .sink { HudHelper.instance.show(banner: .removedFromWatchlist) } - .store(in: &cancellables) - - $filter - .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.sync(filter: $0) } - .store(in: &cancellables) - - sync(state: viewModel.state) - } - - override func didPresentSearch() { - super.didPresentSearch() - - stat(page: .markets, event: .open(page: .marketSearch)) - } - - private func sync(state: MarketViewModel.State) { - self.state = state - - switch state { - case .idle: - tableView.isHidden = true - notFoundPlaceholder.isHidden = true - case .placeholder: - tableView.reload() - tableView.setContentOffset(CGPoint(x: 0, y: -tableView.adjustedContentInset.top), animated: false) - tableView.isHidden = false - notFoundPlaceholder.isHidden = true - case let .searchResults(fullCoins): - tableView.reload() - tableView.isHidden = false - notFoundPlaceholder.isHidden = !fullCoins.isEmpty - } - } - - private func sync(filter: String?) { - viewModel.onUpdate(searchActive: searchController.isActive, filter: filter ?? "") - } - - private func onSelectTab(index: Int) { - guard index < MarketModule.TabOld.allCases.count else { - return - } - - let tab = MarketModule.TabOld.allCases[index] - - viewModel.currentTab = tab - - stat(page: .markets, event: .switchTab(tab: tab.statTab)) - } - - private func setViewPager(tab: MarketModule.TabOld) { - pageViewController.setViewControllers([viewController(tab: tab)], direction: .forward, animated: false) - } - - private func viewController(tab: MarketModule.TabOld) -> UIViewController { - switch tab { - case .overview: return marketOverviewViewController ?? UIViewController() - case .posts: return postViewController - case .watchlist: return watchlistViewController - } - } - - @objc private func onTapFilter() { - // let viewController = MarketAdvancedSearchModule.viewController() - // present(ThemeNavigationController(rootViewController: viewController), animated: true) - - // stat(page: .markets, event: .open(page: .advancedSearch)) - } - - func willPresentSearchController(_: UISearchController) { - viewModel.onUpdate(searchActive: true, filter: filter ?? "") - } - - func willDismissSearchController(_: UISearchController) { - viewModel.onUpdate(searchActive: false, filter: filter ?? "") - } -} - -extension MarketViewController: SectionsDataSource { - private func onSelect(fullCoin: FullCoin, statSection: StatSection) { - let coinUid = fullCoin.coin.uid - - guard let module = CoinPageModule.viewController(coinUid: coinUid) else { - return - } - - DispatchQueue.global().async { [weak self] in - self?.viewModel.handleOpen(coinUid: coinUid) - } - - present(module, animated: true) - - stat(page: .marketSearch, section: statSection, event: .openCoin(coinUid: coinUid)) - } - - private func rowActions(coinUid: String) -> [RowAction] { - let type: RowActionType - let iconName: String - let action: (UITableViewCell?) -> Void - - if viewModel.isFavorite(coinUid: coinUid) { - type = .destructive - iconName = "star_off_24" - action = { [weak self] _ in - self?.viewModel.unfavorite(coinUid: coinUid) - } - } else { - type = .additive - iconName = "star_24" - action = { [weak self] _ in - self?.viewModel.favorite(coinUid: coinUid) - } - } - - return [ - RowAction( - pattern: .icon(image: UIImage(named: iconName)?.withTintColor(type.iconColor), background: type.backgroundColor), - action: action - ), - ] - } - - private func rows(fullCoins: [FullCoin], statSection: StatSection) -> [RowProtocol] { - fullCoins.enumerated().map { index, fullCoin in - let coin = fullCoin.coin - let isLast = index == fullCoins.count - 1 - - return CellBuilderNew.row( - rootElement: .hStack([ - .image32 { component in - component.setImage(urlString: coin.imageUrl, placeholder: UIImage(named: "placeholder_circle_32")) - }, - .vStackCentered([ - .text { component in - component.font = .body - component.textColor = .themeLeah - component.text = coin.code - }, - .margin(3), - .text { component in - component.font = .subhead2 - component.textColor = .themeGray - component.text = coin.name - }, - ]), - ]), - tableView: tableView, - id: "coin_\(coin.uid)", - height: .heightDoubleLineCell, - autoDeselect: true, - rowActionProvider: { [weak self] in self?.rowActions(coinUid: coin.uid) ?? [] }, - bind: { cell in - cell.set(backgroundStyle: .transparent, isLast: isLast) - }, - action: { [weak self] in - self?.onSelect(fullCoin: fullCoin, statSection: statSection) - } - ) - } - } - - func buildSections() -> [SectionProtocol] { - switch state { - case .idle: - return [] - case let .placeholder(recentFullCoins, popularFullCoins): - var sections = [SectionProtocol]() - - if !recentFullCoins.isEmpty { - sections.append( - Section( - id: "recent", - headerState: .cellType( - hash: "recent", - binder: { (view: TransactionDateHeaderView) in - view.text = "market.search.recent".localized - }, - dynamicHeight: { _ in .heightSingleLineCell } - ), - rows: rows(fullCoins: recentFullCoins, statSection: .recent) - ) - ) - } - - if !popularFullCoins.isEmpty { - sections.append( - Section( - id: "popular", - headerState: .cellType( - hash: "popular", - binder: { (view: TransactionDateHeaderView) in - view.text = "market.search.popular".localized - }, - dynamicHeight: { _ in .heightSingleLineCell } - ), - rows: rows(fullCoins: popularFullCoins, statSection: .popular) - ) - ) - } - - return sections - case let .searchResults(fullCoins): - return [ - Section( - id: "coins", - rows: rows(fullCoins: fullCoins, statSection: .searchResults) - ), - ] - } - } -} - -extension MarketViewController: IPresentDelegate { - func present(viewController: UIViewController) { - navigationController?.present(viewController, animated: true) - } - - 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 deleted file mode 100644 index d7196e3612..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketViewModel.swift +++ /dev/null @@ -1,115 +0,0 @@ -import Combine -import MarketKit - -class MarketViewModel { - private let keyTab = "market-tab" - private let keyRecentCoinUids = "market-recent-coin-uids" - - private let userDefaultsStorage = App.shared.userDefaultsStorage - private let launchScreenManager = App.shared.launchScreenManager - private let marketKit = App.shared.marketKit - private let watchlistManager = App.shared.watchlistManager - - @Published var currentTab: MarketModule.TabOld { - didSet { - userDefaultsStorage.set(value: currentTab.rawValue, for: keyTab) - } - } - - @Published private(set) var state: State = .idle - - private var recentCoinUids: [String] { - didSet { - userDefaultsStorage.set(value: recentCoinUids.joined(separator: ","), for: keyRecentCoinUids) - } - } - - private let favoritedSubject = PassthroughSubject() - private let unfavoritedSubject = PassthroughSubject() - - init() { - let currentTab: MarketModule.TabOld - - switch launchScreenManager.launchScreen { - case .auto: - if let storedValue: String = userDefaultsStorage.value(for: keyTab), let storedTab = MarketModule.TabOld(rawValue: storedValue) { - currentTab = storedTab - } else { - currentTab = .overview - } - case .balance, .marketOverview: - currentTab = .overview - case .watchlist: - currentTab = .watchlist - } - - self.currentTab = currentTab - - let recentCoinsUidsRaw: String = userDefaultsStorage.value(for: keyRecentCoinUids) ?? "" - recentCoinUids = recentCoinsUidsRaw.components(separatedBy: ",") - } -} - -extension MarketViewModel { - var favoritedPublisher: AnyPublisher { - favoritedSubject.eraseToAnyPublisher() - } - - var unfavoritedPublisher: AnyPublisher { - unfavoritedSubject.eraseToAnyPublisher() - } - - func onUpdate(searchActive: Bool, filter: String) { - if searchActive { - if filter.isEmpty { - let recentMarketFullCoins = (try? marketKit.fullCoins(coinUids: recentCoinUids)) ?? [] - let recentFullCoins = recentCoinUids.compactMap { coinUid in recentMarketFullCoins.first { $0.coin.uid == coinUid } } - - let popularFullCoins = (try? marketKit.topFullCoins()) ?? [] - - state = .placeholder(recentFullCoins: recentFullCoins, popularFullCoins: popularFullCoins) - } else { - state = .searchResults(fullCoins: (try? marketKit.fullCoins(filter: filter)) ?? []) - } - } else { - state = .idle - } - } - - func isFavorite(coinUid: String) -> Bool { - watchlistManager.isWatched(coinUid: coinUid) - } - - func favorite(coinUid: String) { - watchlistManager.add(coinUid: coinUid) - favoritedSubject.send() - - stat(page: .marketSearch, event: .addToWatchlist(coinUid: coinUid)) - } - - func unfavorite(coinUid: String) { - watchlistManager.remove(coinUid: coinUid) - unfavoritedSubject.send() - - stat(page: .marketSearch, event: .removeFromWatchlist(coinUid: coinUid)) - } - - func handleOpen(coinUid: String) { - var recentCoinUids = recentCoinUids - - if let index = recentCoinUids.firstIndex(of: coinUid) { - recentCoinUids.remove(at: index) - } - - recentCoinUids.insert(coinUid, at: 0) - self.recentCoinUids = Array(recentCoinUids.prefix(5)) - } -} - -extension MarketViewModel { - enum State { - case idle - case placeholder(recentFullCoins: [FullCoin], popularFullCoins: [FullCoin]) - case searchResults(fullCoins: [FullCoin]) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistDecorator.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistDecorator.swift deleted file mode 100644 index 9de69327d3..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistDecorator.swift +++ /dev/null @@ -1,57 +0,0 @@ -import MarketKit - -class MarketWatchlistDecorator { - typealias Item = MarketInfo - - private let service: IMarketListDecoratorService - - var priceChangeType: MarketModule.PriceChangeType - - init(service: IMarketListDecoratorService) { - self.service = service - - priceChangeType = MarketModule.PriceChangeType.sortingTypes.at(index: service.initialIndex) ?? .day - } -} - -extension MarketWatchlistDecorator: IMarketSingleSortHeaderDecorator { - var allFields: [String] { - MarketModule.PriceChangeType.sortingTypes.map(\.shortTitle) - } - - var currentFieldIndex: Int { - MarketModule.PriceChangeType.sortingTypes.firstIndex(of: priceChangeType) ?? 0 - } - - func setCurrentField(index: Int) { - priceChangeType = MarketModule.PriceChangeType.sortingTypes.at(index: index) ?? .day - service.onUpdate(index: index) - - stat(page: .watchlist, event: .switchPeriod(period: priceChangeType.statPeriod)) - } -} - -extension MarketWatchlistDecorator: IMarketListDecorator { - func listViewItem(item marketInfo: MarketInfo) -> MarketModule.ListViewItem { - let currency = service.currency - - let price = marketInfo.price.flatMap { ValueFormatter.instance.formatFull(currency: currency, value: $0) } ?? "n/a".localized - - let dataValue: MarketModule.MarketDataValue - - dataValue = .diff(marketInfo.priceChangeValue(type: priceChangeType)) - - 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 - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistModule.swift deleted file mode 100644 index 6a10b26871..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistModule.swift +++ /dev/null @@ -1,25 +0,0 @@ -import UIKit - -enum MarketWatchlistModule { - static func viewController() -> MarketWatchlistViewController { - let service = MarketWatchlistService( - marketKit: App.shared.marketKit, - currencyManager: App.shared.currencyManager, - watchlistManager: App.shared.watchlistManager, - appManager: App.shared.appManager, - userDefaultsStorage: App.shared.userDefaultsStorage - ) - let watchlistToggleService = MarketWatchlistToggleService( - coinUidService: service, - watchlistManager: App.shared.watchlistManager, - statPage: .watchlist - ) - - let decorator = MarketWatchlistDecorator(service: service) - let viewModel = MarketWatchlistViewModelOld(service: service) - let headerViewModel = MarketSingleSortHeaderViewModel(service: service, decorator: decorator) - let listViewModel = MarketListWatchViewModel(service: service, watchlistToggleService: watchlistToggleService, decorator: decorator) - - return MarketWatchlistViewController(viewModel: viewModel, listViewModel: listViewModel, headerViewModel: headerViewModel) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistService.swift deleted file mode 100644 index 714537a6d0..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistService.swift +++ /dev/null @@ -1,153 +0,0 @@ -import Combine -import HsExtensions -import MarketKit -import RxRelay -import RxSwift - -class MarketWatchlistService: IMarketSingleSortHeaderService { - typealias Item = MarketInfo - - private let keySortDirectionField = "market-watchlist-sort-direction-field" - private let keyPriceChangeField = "market-watchlist-price-change-field" - - private let marketKit: MarketKit.Kit - private let currencyManager: CurrencyManager - private let watchlistManager: WatchlistManager - private let appManager: IAppManager - private let userDefaultsStorage: UserDefaultsStorage - private let disposeBag = DisposeBag() - private var cancellables = Set() - private var tasks = Set() - - @PostPublished private(set) var state: MarketListServiceState = .loading - - private var coinUids = [String]() - - var sortDirectionAscending: Bool { - didSet { - userDefaultsStorage.set(value: sortDirectionAscending, for: keySortDirectionField) - syncIfPossible() - - stat(page: .watchlist, event: .toggleSortDirection) - } - } - - init(marketKit: MarketKit.Kit, currencyManager: CurrencyManager, watchlistManager: WatchlistManager, appManager: IAppManager, userDefaultsStorage: UserDefaultsStorage) { - self.marketKit = marketKit - self.currencyManager = currencyManager - self.watchlistManager = watchlistManager - self.appManager = appManager - self.userDefaultsStorage = userDefaultsStorage - - sortDirectionAscending = userDefaultsStorage.value(for: keySortDirectionField) ?? false - } - - private func syncCoinUids() { - coinUids = watchlistManager.coinUids - - if case let .loaded(marketInfos, _, _) = state { - let newMarketInfos = marketInfos.filter { marketInfo in - coinUids.contains(marketInfo.fullCoin.coin.uid) - } - - if newMarketInfos.count == coinUids.count { - state = .loaded(items: newMarketInfos, softUpdate: true, reorder: false) - return - } - } - - syncMarketInfos() - } - - private func syncMarketInfos() { - tasks = Set() - - if coinUids.isEmpty { - state = .loaded(items: [], softUpdate: false, reorder: false) - return - } - - if case .failed = state { - state = .loading - } - - Task { [weak self, marketKit, coinUids, currency] in - do { - let marketInfos = try await marketKit.marketInfos(coinUids: coinUids, currencyCode: currency.code) - self?.sync(marketInfos: marketInfos) - } catch { - self?.state = .failed(error: error) - } - }.store(in: &tasks) - } - - private func sync(marketInfos: [MarketInfo], reorder: Bool = false) { - let sortingField: MarketModule.SortingField = sortDirectionAscending ? .topLosers : .topGainers - state = .loaded(items: marketInfos.sorted(sortingField: sortingField, priceChangeType: priceChangeType), softUpdate: false, reorder: reorder) - } - - private func syncIfPossible() { - guard case let .loaded(marketInfos, _, _) = state else { - return - } - - sync(marketInfos: marketInfos, reorder: true) - } -} - -extension MarketWatchlistService: IMarketListService { - var statePublisher: AnyPublisher, Never> { - $state - } - - func load() { - currencyManager.$baseCurrency - .sink { [weak self] _ in - self?.syncMarketInfos() - } - .store(in: &cancellables) - - watchlistManager.coinUidsPublisher - .sink { [weak self] _ in self?.syncCoinUids() } - .store(in: &cancellables) - - subscribe(disposeBag, appManager.willEnterForegroundObservable) { [weak self] in self?.syncMarketInfos() } - - syncCoinUids() - } - - func refresh() { - syncMarketInfos() - stat(page: .watchlist, event: .refresh) - } -} - -extension MarketWatchlistService: IMarketListCoinUidService { - func coinUid(index: Int) -> String? { - guard case let .loaded(marketInfos, _, _) = state, index < marketInfos.count else { - return nil - } - - return marketInfos[index].fullCoin.coin.uid - } -} - -extension MarketWatchlistService: IMarketListDecoratorService { - var initialIndex: Int { - userDefaultsStorage.value(for: keyPriceChangeField) ?? 0 - } - - var currency: Currency { - currencyManager.baseCurrency - } - - var priceChangeType: MarketModule.PriceChangeType { - MarketModule.PriceChangeType.sortingTypes.at(index: initialIndex) ?? .day - } - - func onUpdate(index: Int) { - userDefaultsStorage.set(value: index, for: keyPriceChangeField) - - syncIfPossible() - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewController.swift deleted file mode 100644 index 7e8341ef48..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewController.swift +++ /dev/null @@ -1,42 +0,0 @@ -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class MarketWatchlistViewController: MarketListViewController { - weak var parentNavigationController: UINavigationController? - - private let viewModel: MarketWatchlistViewModelOld - - private let singleSortHeaderView: MarketSingleSortHeaderView - private let placeholderView = PlaceholderView() - - override var viewController: UIViewController? { parentNavigationController } - override var headerView: UITableViewHeaderFooterView? { singleSortHeaderView } - override var emptyView: UIView? { placeholderView } - - init(viewModel: MarketWatchlistViewModelOld, listViewModel: IMarketListViewModel, headerViewModel: MarketSingleSortHeaderViewModel) { - self.viewModel = viewModel - singleSortHeaderView = MarketSingleSortHeaderView(viewModel: headerViewModel, hasTopSeparator: false) - - super.init(listViewModel: listViewModel, statPage: .watchlist) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - placeholderView.image = UIImage(named: "rate_48") - placeholderView.text = "market_watchlist.empty.caption".localized - - viewModel.onLoad() - } - - override func showAddedToWatchlist() {} - - override func showRemovedFromWatchlist() {} -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewModelOld.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewModelOld.swift deleted file mode 100644 index 5f319d5086..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketWatchlist/MarketWatchlistViewModelOld.swift +++ /dev/null @@ -1,13 +0,0 @@ -class MarketWatchlistViewModelOld { - private let service: MarketWatchlistService - - init(service: MarketWatchlistService) { - self.service = service - } -} - -extension MarketWatchlistViewModelOld { - func onLoad() { - service.load() - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketSearchView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Search/MarketSearchView.swift similarity index 96% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketSearchView.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Search/MarketSearchView.swift index 08e4802908..6b8c83f8ef 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketSearchView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Search/MarketSearchView.swift @@ -41,7 +41,7 @@ struct MarketSearchView: View { } } .sheet(item: $presentedFullCoin) { fullCoin in - CoinPageViewNew(coinUid: fullCoin.coin.uid) + CoinPageViewNew(coinUid: fullCoin.coin.uid).ignoresSafeArea() } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketSearchViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Search/MarketSearchViewModel.swift similarity index 100% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketSearchViewModel.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Search/MarketSearchViewModel.swift diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTabView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tab/MarketTabView.swift similarity index 100% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTabView.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Tab/MarketTabView.swift diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTabViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tab/MarketTabViewModel.swift similarity index 100% rename from UnstoppableWallet/UnstoppableWallet/Modules/Market/MarketTabViewModel.swift rename to UnstoppableWallet/UnstoppableWallet/Modules/Market/Tab/MarketTabViewModel.swift diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformHeaderCell.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformHeaderCell.swift deleted file mode 100644 index 7874c7426b..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformHeaderCell.swift +++ /dev/null @@ -1,54 +0,0 @@ -import UIKit - -class TopPlatformHeaderCell: UITableViewCell { - static let height: CGFloat = 108 - - private let titleLabel = UILabel() - private let descriptionLabel = UILabel() - private let rightImageView = UIImageView() - - override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - backgroundColor = .clear - selectionStyle = .none - - contentView.addSubview(titleLabel) - titleLabel.snp.makeConstraints { make in - make.leading.equalToSuperview().inset(CGFloat.margin16) - make.top.equalToSuperview().inset(CGFloat.margin12) - } - - titleLabel.font = .headline1 - titleLabel.textColor = .themeLeah - - contentView.addSubview(descriptionLabel) - descriptionLabel.snp.makeConstraints { make in - make.leading.trailing.equalTo(titleLabel) - make.top.equalTo(titleLabel.snp.bottom).offset(CGFloat.margin8) - } - - descriptionLabel.numberOfLines = 0 - descriptionLabel.font = .subhead2 - descriptionLabel.textColor = .themeGray - - contentView.addSubview(rightImageView) - rightImageView.snp.makeConstraints { make in - make.leading.equalTo(titleLabel.snp.trailing).offset(CGFloat.margin24) - make.trailing.equalToSuperview().inset(CGFloat.margin24) - make.centerY.equalToSuperview() - make.size.equalTo(CGFloat.iconSize32) - } - } - - @available(*, unavailable) - public required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func set(title: String, description: String, imageUrl: String) { - titleLabel.text = title - descriptionLabel.text = description - rightImageView.setImage(withUrlString: imageUrl, placeholder: nil) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformModule.swift deleted file mode 100644 index 3103f82a8d..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformModule.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Chart -import MarketKit -import ThemeKit -import UIKit - -enum TopPlatformModule { - static func viewController(topPlatform: TopPlatform) -> UIViewController { - let service = TopPlatformService(topPlatform: topPlatform, marketKit: App.shared.marketKit) - let listService = MarketFilteredListService(currencyManager: App.shared.currencyManager, provider: service, statPage: .topPlatform) - let watchlistToggleService = MarketWatchlistToggleService(coinUidService: listService, watchlistManager: App.shared.watchlistManager, statPage: .topPlatform) - - let marketCapFetcher = TopPlatformMarketCapFetcher(marketKit: App.shared.marketKit, currencyManager: App.shared.currencyManager, topPlatform: topPlatform) - let chartService = MetricChartService(chartFetcher: marketCapFetcher, interval: .byPeriod(.week1), statPage: .topPlatform) - let factory = MetricChartFactory(currentLocale: LanguageManager.shared.currentLocale) - let chartViewModel = MetricChartViewModel(service: chartService, factory: factory) - - let decorator = MarketListMarketFieldDecorator(service: listService, statPage: .topPlatform) - let viewModel = TopPlatformViewModel(service: service) - let listViewModel = MarketListWatchViewModel(service: listService, watchlistToggleService: watchlistToggleService, decorator: decorator) - let headerViewModel = MarketMultiSortHeaderViewModel(service: listService, decorator: decorator) - - let viewController = TopPlatformViewController(viewModel: viewModel, chartViewModel: chartViewModel, listViewModel: listViewModel, headerViewModel: headerViewModel) - - return ThemeNavigationController(rootViewController: viewController) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformService.swift deleted file mode 100644 index 8ad356c2b7..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformService.swift +++ /dev/null @@ -1,17 +0,0 @@ -import MarketKit - -class TopPlatformService { - let topPlatform: TopPlatform - private let marketKit: MarketKit.Kit - - init(topPlatform: TopPlatform, marketKit: MarketKit.Kit) { - self.topPlatform = topPlatform - self.marketKit = marketKit - } -} - -extension TopPlatformService: IMarketFilteredListProvider { - func marketInfos(currencyCode: String) async throws -> [MarketInfo] { - try await marketKit.topPlatformMarketInfos(blockchain: topPlatform.blockchain.uid, currencyCode: currencyCode) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewController.swift deleted file mode 100644 index 6b0fb725ad..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewController.swift +++ /dev/null @@ -1,84 +0,0 @@ -import SectionsTableView -import SnapKit -import ThemeKit -import UIKit - -class TopPlatformViewController: MarketListViewController { - private let viewModel: TopPlatformViewModel - private let multiSortHeaderView: MarketMultiSortHeaderView - - override var viewController: UIViewController? { self } - override var headerView: UITableViewHeaderFooterView? { multiSortHeaderView } - override var refreshEnabled: Bool { false } - - private let chartViewModel: MetricChartViewModel - private let chartCell: ChartCell - private let chartRow: StaticRow - - init(viewModel: TopPlatformViewModel, chartViewModel: MetricChartViewModel, listViewModel: IMarketListViewModel, headerViewModel: MarketMultiSortHeaderViewModel) { - self.viewModel = viewModel - self.chartViewModel = chartViewModel - multiSortHeaderView = MarketMultiSortHeaderView(viewModel: headerViewModel) - - chartCell = ChartCell(viewModel: chartViewModel, configuration: .baseChart) - chartRow = StaticRow( - cell: chartCell, - id: "chartView", - height: chartCell.cellHeight - ) - - super.init(listViewModel: listViewModel, statPage: .topPlatform) - - multiSortHeaderView.viewController = self - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.largeTitleDisplayMode = .never - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.close".localized, style: .plain, target: self, action: #selector(onTapClose)) - - tableView.registerCell(forClass: TopPlatformHeaderCell.self) - - chartRow.onReady = { [weak chartCell] in chartCell?.onLoad() } - chartViewModel.start() - } - - @objc private func onTapClose() { - dismiss(animated: true) - } - - override func topSections(loaded: Bool) -> [SectionProtocol] { - var sections = [Section( - id: "header", - rows: [ - Row( - id: "header", - height: TopPlatformHeaderCell.height, - bind: { [weak self] cell, _ in - self?.bind(cell: cell) - } - ), - ] - )] - - if loaded { - sections.append(Section(id: "chart", rows: [chartRow])) - } - - return sections - } - - private func bind(cell: TopPlatformHeaderCell) { - cell.set( - title: viewModel.title, - description: viewModel.description, - imageUrl: viewModel.imageUrl - ) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewModel.swift deleted file mode 100644 index 4d5acfd65e..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/TopPlatform/TopPlatformViewModel.swift +++ /dev/null @@ -1,21 +0,0 @@ -class TopPlatformViewModel { - private let service: TopPlatformService - - init(service: TopPlatformService) { - self.service = service - } -} - -extension TopPlatformViewModel { - var title: String { - "top_platform.title".localized(service.topPlatform.blockchain.name) - } - - var description: String { - "top_platform.description".localized(service.topPlatform.blockchain.name) - } - - var imageUrl: String { - service.topPlatform.blockchain.type.imageUrl - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlView.swift index 5c6e7b3318..edc7ec49f1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlView.swift @@ -6,67 +6,65 @@ struct MarketTvlView: View { @StateObject var viewModel: MarketTvlViewModel @StateObject var chartViewModel: MetricChartViewModel @StateObject var watchlistViewModel: WatchlistViewModel - @Binding var isPresented: Bool + + @Environment(\.presentationMode) private var presentationMode @State private var filterBySelectorPresented = false @State private var presentedFullCoin: FullCoin? - init(isPresented: Binding) { + init() { _viewModel = StateObject(wrappedValue: MarketTvlViewModel()) _chartViewModel = StateObject(wrappedValue: MetricChartViewModel.instance(type: .tvlInDefi)) _watchlistViewModel = StateObject(wrappedValue: WatchlistViewModel(page: .globalMetricsTvlInDefi)) - _isPresented = isPresented } var body: some View { - ThemeNavigationView { - ThemeView { - switch viewModel.state { - case .loading: - VStack(spacing: 0) { - header() - Spacer() - ProgressView() - Spacer() - } - case let .loaded(defiCoins): - ThemeList(bottomSpacing: .margin16) { - header() - .listRowBackground(Color.clear) - .listRowInsets(EdgeInsets()) - .listRowSeparator(.hidden) - chart() - .listRowBackground(Color.clear) - .listRowInsets(EdgeInsets()) - .listRowSeparator(.hidden) + ThemeView { + switch viewModel.state { + case .loading: + VStack(spacing: 0) { + header() + Spacer() + ProgressView() + Spacer() + } + case let .loaded(defiCoins): + ThemeList(bottomSpacing: .margin16) { + header() + .listRowBackground(Color.clear) + .listRowInsets(EdgeInsets()) + .listRowSeparator(.hidden) + chart() + .listRowBackground(Color.clear) + .listRowInsets(EdgeInsets()) + .listRowSeparator(.hidden) - list(defiCoins: defiCoins) - } - case .failed: - VStack(spacing: 0) { - header() + list(defiCoins: defiCoins) + } + case .failed: + VStack(spacing: 0) { + header() - SyncErrorView { - viewModel.sync() - } + SyncErrorView { + viewModel.sync() } } } - .navigationBarTitleDisplayMode(.inline) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button("button.close".localized) { - isPresented = false - } + } + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button("button.close".localized) { + presentationMode.wrappedValue.dismiss() } } - .onReceive(chartViewModel.$periodType) { periodType in - viewModel.timePeriod = HsTimePeriod(periodType) ?? .day1 - } - .sheet(item: $presentedFullCoin) { fullCoin in - CoinPageViewNew(coinUid: fullCoin.coin.uid).ignoresSafeArea() - .onFirstAppear { stat(page: .globalMetricsTvlInDefi, event: .openCoin(coinUid: fullCoin.coin.uid)) } - } + } + .onReceive(chartViewModel.$periodType) { periodType in + viewModel.timePeriod = HsTimePeriod(periodType) ?? .day1 + } + .sheet(item: $presentedFullCoin) { fullCoin in + CoinPageViewNew(coinUid: fullCoin.coin.uid).ignoresSafeArea() + .onFirstAppear { stat(page: .globalMetricsTvlInDefi, event: .openCoin(coinUid: fullCoin.coin.uid)) } } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlViewModel.swift index 7571010d77..7cbee06e56 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Tvl/MarketTvlViewModel.swift @@ -63,8 +63,8 @@ class MarketTvlViewModel: ObservableObject { } } .sorted { lhsDefiCoin, rhsDefiCoin in - let lhsTvl = lhsDefiCoin.tvl(platforms: platforms) ?? 0 - let rhsTvl = rhsDefiCoin.tvl(platforms: platforms) ?? 0 + let lhsTvl = tvl(defiCoin: lhsDefiCoin, platforms: platforms) ?? 0 + let rhsTvl = tvl(defiCoin: rhsDefiCoin, platforms: platforms) ?? 0 return asc ? lhsTvl < rhsTvl : lhsTvl > rhsTvl } state = .loaded(defiCoins: defiCoins) @@ -72,6 +72,13 @@ class MarketTvlViewModel: ObservableObject { state = .failed(error: error) } } + + private func tvl(defiCoin: DefiCoin, platforms: MarketTvlViewModel.Platforms) -> Decimal? { + switch platforms { + case .all: return defiCoin.tvl + default: return defiCoin.chainTvls[platforms.chain] + } + } } extension MarketTvlViewModel { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/DropdownSortHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/DropdownSortHeaderView.swift deleted file mode 100644 index 9ad9f54112..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/DropdownSortHeaderView.swift +++ /dev/null @@ -1,97 +0,0 @@ -import ComponentKit -import RxCocoa -import RxSwift -import SnapKit -import ThemeKit -import UIKit - -protocol IDropdownSortHeaderViewModel: AnyObject { - var dropdownTitle: String { get } - var dropdownViewItems: [AlertViewItem] { get } - var dropdownValueDriver: Driver { get } - func onSelectDropdown(index: Int) - - var sortDirectionAscendingDriver: Driver { get } - func onToggleSortDirection() -} - -class DropdownSortHeaderView: UITableViewHeaderFooterView { - private let viewModel: IDropdownSortHeaderViewModel - private let disposeBag = DisposeBag() - - weak var viewController: UIViewController? - - private let dropdownButton = SecondaryButton() - private let sortButton = SecondaryCircleButton() - - init(viewModel: IDropdownSortHeaderViewModel, hasTopSeparator: Bool = true) { - self.viewModel = viewModel - - super.init(reuseIdentifier: nil) - - backgroundView = UIView() - backgroundView?.backgroundColor = .themeNavigationBarBackground - - if hasTopSeparator { - let separatorView = UIView() - contentView.addSubview(separatorView) - separatorView.snp.makeConstraints { maker in - maker.leading.trailing.equalToSuperview() - maker.top.equalToSuperview() - maker.height.equalTo(CGFloat.heightOnePixel) - } - - separatorView.backgroundColor = .themeSteel20 - } - - contentView.addSubview(dropdownButton) - dropdownButton.snp.makeConstraints { maker in - maker.leading.equalToSuperview() - maker.centerY.equalToSuperview() - } - - dropdownButton.set(style: .transparent, image: UIImage(named: "arrow_small_down_20")) - dropdownButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - dropdownButton.addTarget(self, action: #selector(onTapDropdownButton), for: .touchUpInside) - - contentView.addSubview(sortButton) - sortButton.snp.makeConstraints { maker in - maker.trailing.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - } - - sortButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - sortButton.addTarget(self, action: #selector(onTapSortButton), for: .touchUpInside) - - subscribe(disposeBag, viewModel.dropdownValueDriver) { [weak self] in self?.syncDropdownButton(title: $0) } - subscribe(disposeBag, viewModel.sortDirectionAscendingDriver) { [weak self] in self?.syncSortButton(ascending: $0) } - } - - @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 - ) { [weak self] index in - self?.viewModel.onSelectDropdown(index: index) - } - - viewController?.present(alertController, animated: true) - } - - @objc private func onTapSortButton() { - viewModel.onToggleSortDirection() - } - - private func syncDropdownButton(title: String) { - dropdownButton.setTitle(title, for: .normal) - } - - private func syncSortButton(ascending: Bool) { - sortButton.set(image: UIImage(named: ascending ? "sort_l2h_20" : "sort_h2l_20")) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/GradientPercentCircle.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/GradientPercentCircle.swift deleted file mode 100644 index 3fb4b9fe38..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/GradientPercentCircle.swift +++ /dev/null @@ -1,101 +0,0 @@ -import SnapKit -import UIKit - -class GradientPercentCircle: UIView { - static let width: CGFloat = 44 - static let height: CGFloat = 44 - static let gradient = UIImage(named: "Market Metrics Gradient Layer") - static let gradientWidth: CGFloat = 156 - - private let gradientLayer = CALayer() - private let outBoundFrame = CGRect(x: width, y: 0, width: gradientWidth, height: height) - - private var currentValue: CGFloat? = nil - - init() { - super.init(frame: .zero) - - backgroundColor = .clear - layer.cornerRadius = Self.width / 2 - clipsToBounds = true - - gradientLayer.contents = Self.gradient?.cgImage - gradientLayer.frame = outBoundFrame - - layer.addSublayer(gradientLayer) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func position(value: CGFloat) -> CGPoint { - let value = max(-1, min(value, 1)) - - return CGPoint(x: Self.gradientWidth / 2 - ceil(Self.width * (1 - value)), y: Self.height / 2) - } - - private func hide(layer: CALayer, animated: Bool) { - let endX: CGFloat = (currentValue ?? 0) >= 0 ? 1 : -1 - - layer.add(CALayer.moveAnimation(layer: layer, to: position(value: endX)), forKey: CALayer.moveAnimationKey) - layer.add(CALayer.opacityAnimation(layer: layer, hide: true), forKey: CALayer.opacityAnimationKey) - - if !animated { - layer.removeAllAnimations() - } - } - - private func showCompletion(layer: CALayer, value: CGFloat, animated: Bool) { - layer.add(CALayer.moveAnimation(layer: layer, to: position(value: value)), forKey: CALayer.moveAnimationKey) - layer.add(CALayer.opacityAnimation(layer: layer, hide: false), forKey: CALayer.opacityAnimationKey) - - if !animated { - layer.removeAllAnimations() - } - } - - private func show(layer: CALayer, value: CGFloat, animated: Bool) { - CALayer.perform({ - layer.position = position(value: value >= 0 ? 1 : -1) - layer.opacity = 0 - - layer.removeAllAnimations() - }, completion: { [weak self] in - self?.showCompletion(layer: layer, value: value, animated: animated) - - }) - } - - private func move(layer: CALayer, toValue: CGFloat, animated: Bool) { - layer.add(CALayer.moveAnimation(layer: layer, to: position(value: toValue)), forKey: CALayer.moveAnimationKey) - if !animated { - 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) - hide(layer: gradientLayer, animated: animated) - currentValue = nil - } - - return - } - let value = percentValue / 100 - - 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 - currentValue = value - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMetricView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMetricView.swift deleted file mode 100644 index edede2a9d5..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMetricView.swift +++ /dev/null @@ -1,172 +0,0 @@ -import Chart -import ComponentKit -import SnapKit -import ThemeKit -import UIKit - -class MarketMetricView: UIView { - static let height: CGFloat = 104 - - private let titleLabel = UILabel() - private let badgeView = BadgeView() - private let valueLabel = UILabel() - private let diffLabel = DiffLabel() - private let chartView: RateChartView - private let button = UIButton() - - var onTap: (() -> Void)? { - didSet { - button.isUserInteractionEnabled = onTap != nil - } - } - - var alreadyHasData: Bool = false - - init(configuration: ChartConfiguration) { - chartView = RateChartView(configuration: configuration) - - super.init(frame: .zero) - - addSubview(button) - button.snp.makeConstraints { maker in - maker.edges.equalToSuperview() - } - - button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside) - button.isUserInteractionEnabled = false - - updateUI() - - backgroundColor = .themeLawrence - layer.cornerRadius = .cornerRadius12 - layer.cornerCurve = .continuous - clipsToBounds = true - - addSubview(chartView) - chartView.snp.makeConstraints { maker in - maker.leading.trailing.bottom.equalToSuperview().inset(CGFloat.margin12) - maker.height.equalTo(configuration.mainHeight) - } - - chartView.isUserInteractionEnabled = false - - addSubview(titleLabel) - titleLabel.snp.makeConstraints { maker in - maker.leading.top.equalToSuperview().inset(CGFloat.margin12) - } - - titleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) - titleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) - titleLabel.font = .caption - titleLabel.textColor = .themeGray - - addSubview(badgeView) - badgeView.snp.makeConstraints { maker in - maker.top.trailing.equalToSuperview().inset(CGFloat.margin12) - maker.leading.equalTo(titleLabel.snp.trailing) - maker.centerY.equalTo(titleLabel.snp.centerY) - } - - badgeView.set(style: .small) - badgeView.isHidden = true - - addSubview(valueLabel) - valueLabel.snp.makeConstraints { maker in - maker.leading.equalToSuperview().inset(CGFloat.margin12) - maker.top.equalTo(titleLabel.snp.bottom).offset(CGFloat.margin8) - } - - valueLabel.font = .subhead1 - - addSubview(diffLabel) - diffLabel.snp.makeConstraints { maker in - maker.trailing.equalToSuperview().inset(CGFloat.margin12) - maker.leading.equalTo(valueLabel.snp.trailing).offset(CGFloat.margin8) - maker.top.equalTo(titleLabel.snp.bottom).offset(CGFloat.margin8) - } - - diffLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) - diffLabel.textAlignment = .right - diffLabel.font = .subhead1 - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func updateUI() { - button.setBackgroundColor(color: UIColor.themeLawrencePressed, forState: .highlighted) - } - - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - updateUI() - } - - @objc private func didTapButton() { - onTap?() - } -} - -extension MarketMetricView { - var title: String? { - get { titleLabel.text } - set { titleLabel.text = newValue } - } - - var badge: String? { - get { badgeView.text } - set { - badgeView.isHidden = (newValue ?? "").isEmpty - badgeView.text = newValue - } - } - - func set(value: String?, diff: Decimal?, chartData: ChartData?, trend: MovementTrend) { - valueLabel.textColor = value == nil ? .themeGray50 : .themeBran - valueLabel.text = value ?? "n/a".localized - - guard let diffValue = diff else { - diffLabel.set(value: nil) - - return - } - let diff = diffValue - - diffLabel.set(value: diff) - - chartView.setCurve(colorType: trend.chartColorType) - if let chartData { - chartView.set(chartData: chartData, animated: alreadyHasData) - alreadyHasData = true - } else { - alreadyHasData = false - // clear - } - } - - func set(value: String?, diff: String, diffColor: UIColor, chartData: ChartData?, trend: MovementTrend) { - valueLabel.textColor = value == nil ? .themeGray50 : .themeBran - valueLabel.text = value ?? "n/a".localized - - diffLabel.set(text: diff, color: diffColor) - - chartView.setCurve(colorType: trend.chartColorType) - if let chartData { - chartView.set(chartData: chartData, indicators: [], animated: alreadyHasData) - alreadyHasData = true - } else { - alreadyHasData = false - // clear - } - } - - func clear() { - valueLabel.text = nil - diffLabel.clear() - - alreadyHasData = false - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderView.swift deleted file mode 100644 index 3ad3445173..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderView.swift +++ /dev/null @@ -1,117 +0,0 @@ -import ComponentKit -import SnapKit -import ThemeKit -import UIExtensions -import UIKit - -protocol IMarketMultiSortHeaderViewModel { - var sortItems: [String] { get } - var sortIndex: Int { get } - - var leftSelectorItems: [String] { get } - var leftSelectorIndex: Int { get } - - var rightSelectorItems: [String] { get } - var rightSelectorIndex: Int { get } - - func onSelectSort(index: Int) - func onSelectLeft(index: Int) - func onSelectRight(index: Int) -} - -class MarketMultiSortHeaderView: UITableViewHeaderFooterView { - static let height: CGFloat = .heightSingleLineCell - - private let viewModel: IMarketMultiSortHeaderViewModel - weak var viewController: UIViewController? - - private let sortButton = SecondaryButton() - - init(viewModel: IMarketMultiSortHeaderViewModel, hasLeftSelector: Bool = false, hasTopSeparator: Bool = true) { - self.viewModel = viewModel - - super.init(reuseIdentifier: nil) - - backgroundView = UIView() - backgroundView?.backgroundColor = .themeNavigationBarBackground - - if hasTopSeparator { - let separatorView = UIView() - contentView.addSubview(separatorView) - separatorView.snp.makeConstraints { maker in - maker.leading.trailing.equalToSuperview() - maker.top.equalToSuperview() - maker.height.equalTo(CGFloat.heightOnePixel) - } - - separatorView.backgroundColor = .themeSteel20 - } - - contentView.addSubview(sortButton) - sortButton.snp.makeConstraints { maker in - maker.leading.equalToSuperview() - maker.centerY.equalToSuperview() - } - - sortButton.set(style: .transparent, image: UIImage(named: "arrow_small_down_20")) - sortButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - - syncSortButtonTitle() - sortButton.addTarget(self, action: #selector(tapSortButton), for: .touchUpInside) - - let rightSelector = SelectorButton() - - contentView.addSubview(rightSelector) - rightSelector.snp.makeConstraints { maker in - maker.trailing.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - maker.height.equalTo(28) - } - - rightSelector.set(items: viewModel.rightSelectorItems) - rightSelector.setSelected(index: viewModel.rightSelectorIndex) - rightSelector.onSelect = { [weak self] index in - self?.viewModel.onSelectRight(index: index) - } - - if hasLeftSelector { - let leftSelector = SelectorButton() - - contentView.addSubview(leftSelector) - leftSelector.snp.makeConstraints { maker in - maker.trailing.equalTo(rightSelector.snp.leading).offset(-CGFloat.margin8) - maker.centerY.equalToSuperview() - maker.height.equalTo(28) - } - - leftSelector.set(items: viewModel.leftSelectorItems) - leftSelector.setSelected(index: viewModel.leftSelectorIndex) - leftSelector.onSelect = { [weak self] index in - self?.viewModel.onSelectLeft(index: index) - } - } - } - - @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) - } - ) { [weak self] index in - self?.viewModel.onSelectSort(index: index) - self?.syncSortButtonTitle() - } - - viewController?.present(alertController, animated: true) - } - - 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 deleted file mode 100644 index dde0dcb384..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketMultiSortHeaderViewModel.swift +++ /dev/null @@ -1,62 +0,0 @@ -import RxRelay -import RxSwift - -protocol IMarketMultiSortHeaderService: AnyObject { - var marketTop: MarketModule.MarketTop { get set } - var sortingField: MarketModule.SortingField { get set } -} - -extension IMarketMultiSortHeaderService { - var marketTop: MarketModule.MarketTop { - get { .top100 } - set {} - } -} - -class MarketMultiSortHeaderViewModel { - private let service: IMarketMultiSortHeaderService - private let decorator: MarketListMarketFieldDecorator - - init(service: IMarketMultiSortHeaderService, decorator: MarketListMarketFieldDecorator) { - self.service = service - self.decorator = decorator - } -} - -extension MarketMultiSortHeaderViewModel: IMarketMultiSortHeaderViewModel { - var sortItems: [String] { - MarketModule.SortingField.allCases.map(\.title) - } - - var sortIndex: Int { - MarketModule.SortingField.allCases.firstIndex(of: service.sortingField) ?? 0 - } - - var leftSelectorItems: [String] { - MarketModule.MarketTop.allCases.map(\.title) - } - - var leftSelectorIndex: Int { - MarketModule.MarketTop.allCases.firstIndex(of: service.marketTop) ?? 0 - } - - var rightSelectorItems: [String] { - MarketModule.MarketField.allCases.map(\.title) - } - - var rightSelectorIndex: Int { - MarketModule.MarketField.allCases.firstIndex(of: decorator.marketField) ?? 0 - } - - func onSelectSort(index: Int) { - service.sortingField = MarketModule.SortingField.allCases[index] - } - - func onSelectLeft(index: Int) { - service.marketTop = MarketModule.MarketTop.allCases[index] - } - - 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 deleted file mode 100644 index 26e47af632..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderView.swift +++ /dev/null @@ -1,76 +0,0 @@ -import ComponentKit -import RxCocoa -import RxSwift -import SnapKit -import ThemeKit -import UIExtensions -import UIKit - -class MarketSingleSortHeaderView: UITableViewHeaderFooterView { - static let height: CGFloat = .heightSingleLineCell - - private let viewModel: MarketSingleSortHeaderViewModel - private let disposeBag = DisposeBag() - - private let sortButton = SecondaryCircleButton() - - init(viewModel: MarketSingleSortHeaderViewModel, hasTopSeparator: Bool = true) { - self.viewModel = viewModel - - super.init(reuseIdentifier: nil) - - backgroundView = UIView() - backgroundView?.backgroundColor = .themeNavigationBarBackground - - if hasTopSeparator { - let separatorView = UIView() - contentView.addSubview(separatorView) - separatorView.snp.makeConstraints { maker in - maker.leading.trailing.equalToSuperview() - maker.top.equalToSuperview() - maker.height.equalTo(CGFloat.heightOnePixel) - } - - separatorView.backgroundColor = .themeSteel20 - } - - contentView.addSubview(sortButton) - sortButton.snp.makeConstraints { maker in - maker.leading.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - } - - sortButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - sortButton.addTarget(self, action: #selector(onTapSortButton), for: .touchUpInside) - - let fieldSelector = SelectorButton() - - contentView.addSubview(fieldSelector) - fieldSelector.snp.makeConstraints { maker in - maker.trailing.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - maker.height.equalTo(28) - } - - fieldSelector.set(items: viewModel.allFields) - fieldSelector.setSelected(index: viewModel.currentFieldIndex) - fieldSelector.onSelect = { [weak self] index in - self?.viewModel.onSelectField(index: index) - } - - subscribe(disposeBag, viewModel.sortDirectionDriver) { [weak self] in self?.syncSortButton(ascending: $0) } - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc private func onTapSortButton() { - viewModel.onToggleSortDirection() - } - - private func syncSortButton(ascending: Bool) { - sortButton.set(image: UIImage(named: ascending ? "sort_l2h_20" : "sort_h2l_20")) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderViewModel.swift deleted file mode 100644 index 1799b6c29b..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketSingleSortHeaderViewModel.swift +++ /dev/null @@ -1,54 +0,0 @@ -import RxCocoa -import RxRelay -import RxSwift - -protocol IMarketSingleSortHeaderService: AnyObject { - var sortDirectionAscending: Bool { get set } -} - -protocol IMarketSingleSortHeaderDecorator: AnyObject { - var allFields: [String] { get } - var currentFieldIndex: Int { get } - func setCurrentField(index: Int) -} - -class MarketSingleSortHeaderViewModel { - private let service: IMarketSingleSortHeaderService - private let decorator: IMarketSingleSortHeaderDecorator - - private let sortDirectionRelay: BehaviorRelay - - init(service: IMarketSingleSortHeaderService, decorator: IMarketSingleSortHeaderDecorator) { - self.service = service - self.decorator = decorator - - sortDirectionRelay = BehaviorRelay(value: service.sortDirectionAscending) - } -} - -extension MarketSingleSortHeaderViewModel { - var allFields: [String] { - decorator.allFields - } - - var sortDirectionAscending: Bool { - service.sortDirectionAscending - } - - var currentFieldIndex: Int { - decorator.currentFieldIndex - } - - var sortDirectionDriver: Driver { - sortDirectionRelay.asDriver() - } - - func onToggleSortDirection() { - service.sortDirectionAscending = !service.sortDirectionAscending - sortDirectionRelay.accept(service.sortDirectionAscending) - } - - 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 deleted file mode 100644 index 8834ba0b78..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderView.swift +++ /dev/null @@ -1,115 +0,0 @@ -import ComponentKit -import RxCocoa -import RxSwift -import SnapKit -import ThemeKit -import UIExtensions -import UIKit - -class MarketTvlSortHeaderView: UITableViewHeaderFooterView { - static let height: CGFloat = .heightSingleLineCell - - private let viewModel: MarketTvlSortHeaderViewModel - private let disposeBag = DisposeBag() - - weak var viewController: UIViewController? - - private let dropdownButton = SecondaryButton() - private let sortButton = SecondaryCircleButton() - private let marketTvlFieldButton = SecondaryCircleButton() - - init(viewModel: MarketTvlSortHeaderViewModel, hasTopSeparator: Bool = true) { - self.viewModel = viewModel - - super.init(reuseIdentifier: nil) - - backgroundView = UIView() - backgroundView?.backgroundColor = .themeNavigationBarBackground - - if hasTopSeparator { - let separatorView = UIView() - contentView.addSubview(separatorView) - separatorView.snp.makeConstraints { maker in - maker.leading.trailing.equalToSuperview() - maker.top.equalToSuperview() - maker.height.equalTo(CGFloat.heightOnePixel) - } - - separatorView.backgroundColor = .themeSteel20 - } - - contentView.addSubview(dropdownButton) - dropdownButton.snp.makeConstraints { maker in - maker.leading.equalToSuperview() - maker.centerY.equalToSuperview() - } - - dropdownButton.set(style: .transparent, image: UIImage(named: "arrow_small_down_20")) - dropdownButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - dropdownButton.addTarget(self, action: #selector(onTapDropdownButton), for: .touchUpInside) - - marketTvlFieldButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - marketTvlFieldButton.addTarget(self, action: #selector(onTapMarketTvlFieldButton), for: .touchUpInside) - - contentView.addSubview(marketTvlFieldButton) - marketTvlFieldButton.snp.makeConstraints { maker in - maker.trailing.equalToSuperview().inset(CGFloat.margin16) - maker.centerY.equalToSuperview() - } - - contentView.addSubview(sortButton) - sortButton.snp.makeConstraints { maker in - maker.trailing.equalTo(marketTvlFieldButton.snp.leading).offset(-CGFloat.margin16) - maker.centerY.equalToSuperview() - } - - sortButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - sortButton.addTarget(self, action: #selector(onTapSortButton), for: .touchUpInside) - - subscribe(disposeBag, viewModel.platformFieldDriver) { [weak self] in self?.syncDropdownButton(title: $0) } - subscribe(disposeBag, viewModel.sortDirectionDriver) { [weak self] in self?.syncSortButton(ascending: $0) } - subscribe(disposeBag, viewModel.marketTvlFieldDriver) { [weak self] in self?.syncMarketTvlFieldButton(marketTvlField: $0) } - } - - @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 - ) { [weak self] index in - self?.viewModel.onSelectMarketPlatformField(index: index) - } - - viewController?.present(alertController, animated: true) - } - - @objc private func onTapSortButton() { - viewModel.onToggleSortDirection() - } - - private func syncMarketTvlFieldButton(marketTvlField: MarketModule.MarketTvlField) { - let imageName: String - switch marketTvlField { - case .value: imageName = "usd_20" - case .diff: imageName = "percent_20" - } - - marketTvlFieldButton.set(image: UIImage(named: imageName)) - } - - @objc private func onTapMarketTvlFieldButton() { - viewModel.onToggleMarketTvlField() - } - - private func syncDropdownButton(title: String) { - dropdownButton.setTitle(title, for: .normal) - } - - private func syncSortButton(ascending: Bool) { - sortButton.set(image: UIImage(named: ascending ? "sort_l2h_20" : "sort_h2l_20")) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderViewModel.swift deleted file mode 100644 index e64773cc15..0000000000 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Market/Views/MarketTvlSortHeaderViewModel.swift +++ /dev/null @@ -1,75 +0,0 @@ -import RxCocoa -import RxRelay -import RxSwift - -class MarketTvlSortHeaderViewModel { - private let service: MarketGlobalTvlMetricService - private let decorator: MarketListTvlDecorator - - private let platformFieldRelay: BehaviorRelay - private let sortDirectionAscendingRelay: BehaviorRelay - private let marketTvlFieldRelay: BehaviorRelay - - init(service: MarketGlobalTvlMetricService, decorator: MarketListTvlDecorator) { - self.service = service - self.decorator = decorator - - platformFieldRelay = BehaviorRelay(value: service.marketPlatformField.title) - 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) - } - } - - var marketTvlFields: [MarketModule.MarketTvlField] { - MarketModule.MarketTvlField.allCases - } - - var sortDirectionAscending: Bool { - service.sortDirectionAscending - } - - var platformFieldIndex: Int { - MarketModule.MarketPlatformField.allCases.firstIndex(of: service.marketPlatformField) ?? 0 - } - - var marketTvlFieldIndex: Int { - MarketModule.MarketTvlField.allCases.firstIndex(of: service.marketTvlField) ?? 0 - } - - var platformFieldDriver: Driver { - platformFieldRelay.asDriver() - } - - var sortDirectionDriver: Driver { - sortDirectionAscendingRelay.asDriver() - } - - var marketTvlFieldDriver: Driver { - marketTvlFieldRelay.asDriver() - } - - func onToggleSortDirection() { - service.sortDirectionAscending = !service.sortDirectionAscending - sortDirectionAscendingRelay.accept(service.sortDirectionAscending) - } - - func onToggleMarketTvlField() { - switch service.marketTvlField { - case .value: service.marketTvlField = .diff - case .diff: service.marketTvlField = .value - } - marketTvlFieldRelay.accept(service.marketTvlField) - } - - func onSelectMarketPlatformField(index: Int) { - service.marketPlatformField = MarketModule.MarketPlatformField.allCases[index] - platformFieldRelay.accept(service.marketPlatformField.title) - } -} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift index 01fff236a0..10c6dde717 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift @@ -562,16 +562,6 @@ extension MainSettingsViewController: SectionsDataSource { ), isFirst: true ), - tableView.universalRow48( - id: "new-market-tab-switcher", - title: .body("New Market Tab"), - accessoryType: .switch( - isOn: App.shared.localStorage.newMarketTabEnabled, - onSwitch: { enabled in - App.shared.localStorage.newMarketTabEnabled = enabled - } - ) - ), tableView.universalRow48( id: "test-net-switcher", title: .body("TestNet Enabled"),