Replaced SegmentedControl with ScrollableSegmentedControl and SegmentedControl.Selection with ControlSelection everywhere else in app. #3641

pull/3759/head
Jerome Chan 3 years ago
parent 5cb5efc8b4
commit b7d78ab5e4
  1. 12
      AlphaWallet.xcodeproj/project.pbxproj
  2. 6
      AlphaWallet/Core/ViewModels/DropDownViewModel.swift
  3. 8
      AlphaWallet/Core/Views/DropDownView.swift
  4. 23
      AlphaWallet/ScrollableSegmentedControl/ScrollableSegmentedControl.swift
  5. 66
      AlphaWallet/ScrollableSegmentedControl/ScrollableSegmentedControlAdapter.swift
  6. 30
      AlphaWallet/Settings/ViewControllers/SaveCustomRpcOverallViewController.swift
  7. 15
      AlphaWallet/Settings/Views/SaveCustomRpcOverallView.swift
  8. 2
      AlphaWallet/Tokens/ViewControllers/AddHideTokensViewController.swift
  9. 33
      AlphaWallet/Tokens/ViewControllers/TokensViewController.swift
  10. 56
      AlphaWallet/Tokens/ViewModels/SegmentedControlViewModel.swift
  11. 2
      AlphaWallet/Tokens/ViewModels/TokensViewModel.swift
  12. 176
      AlphaWallet/Tokens/Views/SegmentedControl.swift
  13. 2
      AlphaWallet/Transactions/Views/TokenHistoryChartView.swift
  14. 4
      AlphaWallet/Transactions/Views/TokenHistoryPeriodSelectorView.swift
  15. 25
      AlphaWallet/Transactions/Views/TokenPagesContainerView.swift
  16. 37
      AlphaWallet/Wallet/ViewControllers/ImportWalletViewController.swift
  17. 4
      AlphaWallet/Wallet/ViewModels/ImportWalletViewModel.swift

@ -13,7 +13,6 @@
022CED7E277B01E10043287F /* ScrollableSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022CED7B277B01E10043287F /* ScrollableSegmentedControl.swift */; }; 022CED7E277B01E10043287F /* ScrollableSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022CED7B277B01E10043287F /* ScrollableSegmentedControl.swift */; };
022CED7F277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022CED7C277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift */; }; 022CED7F277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022CED7C277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift */; };
022CED80277B01E10043287F /* ScrollableSegmentedControlCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022CED7D277B01E10043287F /* ScrollableSegmentedControlCell.swift */; }; 022CED80277B01E10043287F /* ScrollableSegmentedControlCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022CED7D277B01E10043287F /* ScrollableSegmentedControlCell.swift */; };
022CED82277B04010043287F /* ScrollableSegmentedControlAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022CED81277B04010043287F /* ScrollableSegmentedControlAdapter.swift */; };
023286E0277D793A007D33C5 /* AddMultipleCustomRpcViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023286DF277D793A007D33C5 /* AddMultipleCustomRpcViewController.swift */; }; 023286E0277D793A007D33C5 /* AddMultipleCustomRpcViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023286DF277D793A007D33C5 /* AddMultipleCustomRpcViewController.swift */; };
023286E2277D7960007D33C5 /* AddMultipleCustomRpcView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023286E1277D7960007D33C5 /* AddMultipleCustomRpcView.swift */; }; 023286E2277D7960007D33C5 /* AddMultipleCustomRpcView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023286E1277D7960007D33C5 /* AddMultipleCustomRpcView.swift */; };
023286E4277E79DE007D33C5 /* AddMultipleCustomRpcPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023286E3277E79DE007D33C5 /* AddMultipleCustomRpcPresentationController.swift */; }; 023286E4277E79DE007D33C5 /* AddMultipleCustomRpcPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023286E3277E79DE007D33C5 /* AddMultipleCustomRpcPresentationController.swift */; };
@ -581,7 +580,6 @@
5E7C7C5C350376B83D23154F /* MixpanelCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C758EB5C7B77A0EE6BC9E /* MixpanelCoordinator.swift */; }; 5E7C7C5C350376B83D23154F /* MixpanelCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C758EB5C7B77A0EE6BC9E /* MixpanelCoordinator.swift */; };
5E7C7C60BAF11B0BD135FC1E /* GroupActivityViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7E58DD0CF4E2B35B6ED2 /* GroupActivityViewCell.swift */; }; 5E7C7C60BAF11B0BD135FC1E /* GroupActivityViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7E58DD0CF4E2B35B6ED2 /* GroupActivityViewCell.swift */; };
5E7C7C869A09FD09DCE77EE6 /* ActivityCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C760CC5A9E144BDB5451D /* ActivityCellViewModel.swift */; }; 5E7C7C869A09FD09DCE77EE6 /* ActivityCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C760CC5A9E144BDB5451D /* ActivityCellViewModel.swift */; };
5E7C7C91C5FF48F51134A7DA /* SegmentedControlViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C799AF966DBF0D59DFB20 /* SegmentedControlViewModel.swift */; };
5E7C7C98EAF40E8110241DBD /* NonFungibleTokenViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C783E3ADA4CF9554A0E7D /* NonFungibleTokenViewCell.swift */; }; 5E7C7C98EAF40E8110241DBD /* NonFungibleTokenViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C783E3ADA4CF9554A0E7D /* NonFungibleTokenViewCell.swift */; };
5E7C7CA66F3086000BA3E72C /* GasEstimates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7B19FDDF5D0535243682 /* GasEstimates.swift */; }; 5E7C7CA66F3086000BA3E72C /* GasEstimates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7B19FDDF5D0535243682 /* GasEstimates.swift */; };
5E7C7CA7562FD8352967EFBD /* PromptBackupWalletAfterReceivingEtherViewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7F6C71DDC98D7DF754B2 /* PromptBackupWalletAfterReceivingEtherViewViewModel.swift */; }; 5E7C7CA7562FD8352967EFBD /* PromptBackupWalletAfterReceivingEtherViewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7F6C71DDC98D7DF754B2 /* PromptBackupWalletAfterReceivingEtherViewViewModel.swift */; };
@ -632,7 +630,6 @@
5E7C7E68425E20834B898D06 /* AppLocale.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7B29A9E728402D144C05 /* AppLocale.swift */; }; 5E7C7E68425E20834B898D06 /* AppLocale.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7B29A9E728402D144C05 /* AppLocale.swift */; };
5E7C7E747797C72C67BBDFF4 /* ABIEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7185AA9F93D4F0B67AF7 /* ABIEncoder.swift */; }; 5E7C7E747797C72C67BBDFF4 /* ABIEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7185AA9F93D4F0B67AF7 /* ABIEncoder.swift */; };
5E7C7E7AEF01B9D170228342 /* TimeEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C73EFA9494B31C683A287 /* TimeEntryField.swift */; }; 5E7C7E7AEF01B9D170228342 /* TimeEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C73EFA9494B31C683A287 /* TimeEntryField.swift */; };
5E7C7E7B095F9824FFA244FB /* SegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C73BD3FD2C2844F5DEA45 /* SegmentedControl.swift */; };
5E7C7E83AD74AFB0C717EAC0 /* DappsHomeViewControllerHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C799D2B7D91072FC0050B /* DappsHomeViewControllerHeaderView.swift */; }; 5E7C7E83AD74AFB0C717EAC0 /* DappsHomeViewControllerHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C799D2B7D91072FC0050B /* DappsHomeViewControllerHeaderView.swift */; };
5E7C7E8E89279EB6DB805620 /* SuccessOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7FF2EF77D5004A600DDB /* SuccessOverlayView.swift */; }; 5E7C7E8E89279EB6DB805620 /* SuccessOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7FF2EF77D5004A600DDB /* SuccessOverlayView.swift */; };
5E7C7EAAF2BD4D12987968E4 /* MyDappCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7324C9AC776E3A7B43D1 /* MyDappCellViewModel.swift */; }; 5E7C7EAAF2BD4D12987968E4 /* MyDappCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7324C9AC776E3A7B43D1 /* MyDappCellViewModel.swift */; };
@ -1098,7 +1095,6 @@
022CED7B277B01E10043287F /* ScrollableSegmentedControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentedControl.swift; sourceTree = "<group>"; }; 022CED7B277B01E10043287F /* ScrollableSegmentedControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentedControl.swift; sourceTree = "<group>"; };
022CED7C277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentedControlHighlightableLineView.swift; sourceTree = "<group>"; }; 022CED7C277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentedControlHighlightableLineView.swift; sourceTree = "<group>"; };
022CED7D277B01E10043287F /* ScrollableSegmentedControlCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentedControlCell.swift; sourceTree = "<group>"; }; 022CED7D277B01E10043287F /* ScrollableSegmentedControlCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentedControlCell.swift; sourceTree = "<group>"; };
022CED81277B04010043287F /* ScrollableSegmentedControlAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentedControlAdapter.swift; sourceTree = "<group>"; };
023286DF277D793A007D33C5 /* AddMultipleCustomRpcViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMultipleCustomRpcViewController.swift; sourceTree = "<group>"; }; 023286DF277D793A007D33C5 /* AddMultipleCustomRpcViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMultipleCustomRpcViewController.swift; sourceTree = "<group>"; };
023286E1277D7960007D33C5 /* AddMultipleCustomRpcView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMultipleCustomRpcView.swift; sourceTree = "<group>"; }; 023286E1277D7960007D33C5 /* AddMultipleCustomRpcView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMultipleCustomRpcView.swift; sourceTree = "<group>"; };
023286E3277E79DE007D33C5 /* AddMultipleCustomRpcPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMultipleCustomRpcPresentationController.swift; sourceTree = "<group>"; }; 023286E3277E79DE007D33C5 /* AddMultipleCustomRpcPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMultipleCustomRpcPresentationController.swift; sourceTree = "<group>"; };
@ -1413,7 +1409,6 @@
5E7C73883FBA3C4BAF889E97 /* Constants+Credentials.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Constants+Credentials.swift"; sourceTree = "<group>"; }; 5E7C73883FBA3C4BAF889E97 /* Constants+Credentials.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Constants+Credentials.swift"; sourceTree = "<group>"; };
5E7C739774984CDE1D3D7555 /* VerifySeedPhraseViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerifySeedPhraseViewModel.swift; sourceTree = "<group>"; }; 5E7C739774984CDE1D3D7555 /* VerifySeedPhraseViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerifySeedPhraseViewModel.swift; sourceTree = "<group>"; };
5E7C73BA4FF25754ACB41255 /* CreateInitialWalletViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateInitialWalletViewModel.swift; sourceTree = "<group>"; }; 5E7C73BA4FF25754ACB41255 /* CreateInitialWalletViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateInitialWalletViewModel.swift; sourceTree = "<group>"; };
5E7C73BD3FD2C2844F5DEA45 /* SegmentedControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedControl.swift; sourceTree = "<group>"; };
5E7C73BF5CE15E6D7AFC3F0C /* ChooseSendPrivateTransactionsProviderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChooseSendPrivateTransactionsProviderViewModel.swift; sourceTree = "<group>"; }; 5E7C73BF5CE15E6D7AFC3F0C /* ChooseSendPrivateTransactionsProviderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChooseSendPrivateTransactionsProviderViewModel.swift; sourceTree = "<group>"; };
5E7C73BFE30E0D43E97806EF /* SelectionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewCell.swift; sourceTree = "<group>"; }; 5E7C73BFE30E0D43E97806EF /* SelectionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewCell.swift; sourceTree = "<group>"; };
5E7C73CC82B9877AF4A42333 /* ShowSeedPhraseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShowSeedPhraseViewController.swift; sourceTree = "<group>"; }; 5E7C73CC82B9877AF4A42333 /* ShowSeedPhraseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShowSeedPhraseViewController.swift; sourceTree = "<group>"; };
@ -1585,7 +1580,6 @@
5E7C7977C40B6A4855DBB4A9 /* Activity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Activity.swift; sourceTree = "<group>"; }; 5E7C7977C40B6A4855DBB4A9 /* Activity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Activity.swift; sourceTree = "<group>"; };
5E7C7981AB6584B25C72D46B /* LockEnterPasscodeCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockEnterPasscodeCoordinator.swift; sourceTree = "<group>"; }; 5E7C7981AB6584B25C72D46B /* LockEnterPasscodeCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockEnterPasscodeCoordinator.swift; sourceTree = "<group>"; };
5E7C799836611BEE66000EE1 /* DappsHomeHeaderViewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DappsHomeHeaderViewViewModel.swift; sourceTree = "<group>"; }; 5E7C799836611BEE66000EE1 /* DappsHomeHeaderViewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DappsHomeHeaderViewViewModel.swift; sourceTree = "<group>"; };
5E7C799AF966DBF0D59DFB20 /* SegmentedControlViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedControlViewModel.swift; sourceTree = "<group>"; };
5E7C799D2B7D91072FC0050B /* DappsHomeViewControllerHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DappsHomeViewControllerHeaderView.swift; sourceTree = "<group>"; }; 5E7C799D2B7D91072FC0050B /* DappsHomeViewControllerHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DappsHomeViewControllerHeaderView.swift; sourceTree = "<group>"; };
5E7C799E4784815CB0202820 /* Core.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Core.swift; sourceTree = "<group>"; }; 5E7C799E4784815CB0202820 /* Core.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Core.swift; sourceTree = "<group>"; };
5E7C79C0C9631E4DFC4A40DF /* TokenScriptCard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenScriptCard.swift; sourceTree = "<group>"; }; 5E7C79C0C9631E4DFC4A40DF /* TokenScriptCard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenScriptCard.swift; sourceTree = "<group>"; };
@ -2193,7 +2187,6 @@
022CED7B277B01E10043287F /* ScrollableSegmentedControl.swift */, 022CED7B277B01E10043287F /* ScrollableSegmentedControl.swift */,
022CED7D277B01E10043287F /* ScrollableSegmentedControlCell.swift */, 022CED7D277B01E10043287F /* ScrollableSegmentedControlCell.swift */,
022CED7C277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift */, 022CED7C277B01E10043287F /* ScrollableSegmentedControlHighlightableLineView.swift */,
022CED81277B04010043287F /* ScrollableSegmentedControlAdapter.swift */,
); );
path = ScrollableSegmentedControl; path = ScrollableSegmentedControl;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2808,7 +2801,6 @@
5E7C7BEDC786FB048A1DD9A8 /* WKWebViewExtension.swift */, 5E7C7BEDC786FB048A1DD9A8 /* WKWebViewExtension.swift */,
5E7C78402B975F69A72E8C04 /* TokensViewControllerTableViewHeader.swift */, 5E7C78402B975F69A72E8C04 /* TokensViewControllerTableViewHeader.swift */,
5E7C7FB7C3FB2A9CC0CC51D7 /* TokensViewControllerTableViewSectionHeader.swift */, 5E7C7FB7C3FB2A9CC0CC51D7 /* TokensViewControllerTableViewSectionHeader.swift */,
5E7C73BD3FD2C2844F5DEA45 /* SegmentedControl.swift */,
5E7C78FF8A5682C27E15B488 /* UITableViewCell+TokenCell.swift */, 5E7C78FF8A5682C27E15B488 /* UITableViewCell+TokenCell.swift */,
87D1757724ADAEEB002130D2 /* BlockchainTagLabel.swift */, 87D1757724ADAEEB002130D2 /* BlockchainTagLabel.swift */,
87620027266E14A80059B05A /* PopularTokenViewCell.swift */, 87620027266E14A80059B05A /* PopularTokenViewCell.swift */,
@ -2859,7 +2851,6 @@
5E7C76B386CFE74302944BB0 /* TokenViewControllerViewModel.swift */, 5E7C76B386CFE74302944BB0 /* TokenViewControllerViewModel.swift */,
5E7C7B5838E12930000D5029 /* TokenViewControllerTransactionCellViewModel.swift */, 5E7C7B5838E12930000D5029 /* TokenViewControllerTransactionCellViewModel.swift */,
5E7C75506A766DF9B746E62F /* TokenInstanceViewModel.swift */, 5E7C75506A766DF9B746E62F /* TokenInstanceViewModel.swift */,
5E7C799AF966DBF0D59DFB20 /* SegmentedControlViewModel.swift */,
8782035E2431FBC300792F12 /* ShowAddHideTokensViewModel.swift */, 8782035E2431FBC300792F12 /* ShowAddHideTokensViewModel.swift */,
87C8018B24350174007648CF /* AddHideTokenSectionHeaderViewModel.swift */, 87C8018B24350174007648CF /* AddHideTokenSectionHeaderViewModel.swift */,
87D1757924ADAF07002130D2 /* BlockchainTagLabelViewModel.swift */, 87D1757924ADAF07002130D2 /* BlockchainTagLabelViewModel.swift */,
@ -5666,7 +5657,6 @@
files = ( files = (
29C70C7F20199AEB0072E454 /* WKWebViewConfiguration.swift in Sources */, 29C70C7F20199AEB0072E454 /* WKWebViewConfiguration.swift in Sources */,
73ACEF0120163ED4003DD71D /* LockViewModel.swift in Sources */, 73ACEF0120163ED4003DD71D /* LockViewModel.swift in Sources */,
022CED82277B04010043287F /* ScrollableSegmentedControlAdapter.swift in Sources */,
29AD8A041F93D6CD008E10E7 /* Constants.swift in Sources */, 29AD8A041F93D6CD008E10E7 /* Constants.swift in Sources */,
2963B6B11F9891F5003063C1 /* UIButton.swift in Sources */, 2963B6B11F9891F5003063C1 /* UIButton.swift in Sources */,
29F114F21FA7966300114A29 /* PrivateKeyRule.swift in Sources */, 29F114F21FA7966300114A29 /* PrivateKeyRule.swift in Sources */,
@ -6433,8 +6423,6 @@
5E7C726DE238609C1FB2E320 /* Constants+Credentials.swift in Sources */, 5E7C726DE238609C1FB2E320 /* Constants+Credentials.swift in Sources */,
5E7C70D06F3264745222BEA9 /* ENSReverseLookupCoordinator.swift in Sources */, 5E7C70D06F3264745222BEA9 /* ENSReverseLookupCoordinator.swift in Sources */,
5E7C7C006370184D1E15C788 /* ENSReverseLookupEncode.swift in Sources */, 5E7C7C006370184D1E15C788 /* ENSReverseLookupEncode.swift in Sources */,
5E7C7E7B095F9824FFA244FB /* SegmentedControl.swift in Sources */,
5E7C7C91C5FF48F51134A7DA /* SegmentedControlViewModel.swift in Sources */,
5E7C7F3CB1F280E6795A479C /* EventOrigin.swift in Sources */, 5E7C7F3CB1F280E6795A479C /* EventOrigin.swift in Sources */,
5E7C7A2DBFF7FB3B8B5DEB1B /* EventInstance.swift in Sources */, 5E7C7A2DBFF7FB3B8B5DEB1B /* EventInstance.swift in Sources */,
5E7C7D918B514B4C2F8DF296 /* EventSourceCoordinator.swift in Sources */, 5E7C7D918B514B4C2F8DF296 /* EventSourceCoordinator.swift in Sources */,

@ -13,10 +13,10 @@ protocol DropDownItemType: Equatable {
struct DropDownViewModel<T: DropDownItemType> { struct DropDownViewModel<T: DropDownItemType> {
let selectionItems: [T] let selectionItems: [T]
var selected: SegmentedControl.Selection var selected: ControlSelection
var placeholder: String = R.string.localizable.sortTokensSortBy("-") var placeholder: String = R.string.localizable.sortTokensSortBy("-")
func placeholder(for selection: SegmentedControl.Selection) -> String { func placeholder(for selection: ControlSelection) -> String {
switch selection { switch selection {
case .unselected: case .unselected:
return placeholder return placeholder
@ -37,7 +37,7 @@ struct DropDownViewModel<T: DropDownItemType> {
]) ])
} }
static func elementSelection(of selected: T, in selectionItems: [T]) -> SegmentedControl.Selection { static func elementSelection(of selected: T, in selectionItems: [T]) -> ControlSelection {
guard let index = selectionItems.firstIndex(where: { $0 == selected }) else { guard let index = selectionItems.firstIndex(where: { $0 == selected }) else {
return .unselected return .unselected
} }

@ -8,7 +8,7 @@
import UIKit import UIKit
protocol DropDownViewDelegate: class { protocol DropDownViewDelegate: class {
func filterDropDownViewDidChange(selection: SegmentedControl.Selection) func filterDropDownViewDidChange(selection: ControlSelection)
} }
final class DropDownView<T: DropDownItemType>: UIView, ReusableTableHeaderViewType, UIPickerViewDelegate, UIPickerViewDataSource { final class DropDownView<T: DropDownItemType>: UIView, ReusableTableHeaderViewType, UIPickerViewDelegate, UIPickerViewDataSource {
@ -29,7 +29,7 @@ final class DropDownView<T: DropDownItemType>: UIView, ReusableTableHeaderViewTy
return viewModel.attributedString(item: viewModel.selectionItems[row]) return viewModel.attributedString(item: viewModel.selectionItems[row])
} }
private var selected: SegmentedControl.Selection private var selected: ControlSelection
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
selected = .selected(UInt(row)) selected = .selected(UInt(row))
} }
@ -109,13 +109,13 @@ final class DropDownView<T: DropDownItemType>: UIView, ReusableTableHeaderViewTy
delegate?.filterDropDownViewDidChange(selection: viewModel.selected) delegate?.filterDropDownViewDidChange(selection: viewModel.selected)
} }
private func configure(selection: SegmentedControl.Selection) { private func configure(selection: ControlSelection) {
let placeholder = viewModel.placeholder(for: selection) let placeholder = viewModel.placeholder(for: selection)
selectionButton.setTitle(placeholder, for: .normal) selectionButton.setTitle(placeholder, for: .normal)
selectionButton.semanticContentAttribute = .forceRightToLeft selectionButton.semanticContentAttribute = .forceRightToLeft
} }
func value(from selection: SegmentedControl.Selection) -> T? { func value(from selection: ControlSelection) -> T? {
switch selection { switch selection {
case .unselected: case .unselected:
return nil return nil

@ -18,14 +18,12 @@ struct ScrollableSegmentedControlConfiguration {
} }
class ScrollableSegmentedControl: UIControl { enum ControlSelection: Equatable {
case selected(UInt)
enum Selection { case unselected
case unselected }
case selected(Int)
}
// Only if not scrollable (total cells width + spacing < control width). class ScrollableSegmentedControl: UIControl, ReusableTableHeaderViewType {
enum Alignment { enum Alignment {
case leading case leading
@ -44,12 +42,11 @@ class ScrollableSegmentedControl: UIControl {
private var previousWidth: CGFloat = 0.0 private var previousWidth: CGFloat = 0.0
private var scrollViewHeightConstraint: NSLayoutConstraint? private var scrollViewHeightConstraint: NSLayoutConstraint?
private var scrollViewPositionConstraints: [NSLayoutConstraint] = [] private var scrollViewPositionConstraints: [NSLayoutConstraint] = []
private var _selectedSegment: Selection = .unselected private var _selectedSegment: ControlSelection = .unselected
// MARK: Public // MARK: Public
var selectedSegment: ControlSelection {
var selectedSegment: Selection { _selectedSegment
return _selectedSegment
} }
// MARK: - UI Elements // MARK: - UI Elements
@ -129,13 +126,13 @@ class ScrollableSegmentedControl: UIControl {
func setSelection(cellIndex: Int) { func setSelection(cellIndex: Int) {
guard cellIndex < cells.count, cellIndex >= 0 else { return } guard cellIndex < cells.count, cellIndex >= 0 else { return }
_selectedSegment = .selected(cellIndex) _selectedSegment = .selected(UInt(cellIndex))
highlightCell(cellIndex: cellIndex) highlightCell(cellIndex: cellIndex)
} }
func setSelection(cell: ScrollableSegmentedControlCell) { func setSelection(cell: ScrollableSegmentedControlCell) {
guard let cellIndex = cells.firstIndex(of: cell) else { return } guard let cellIndex = cells.firstIndex(of: cell) else { return }
_selectedSegment = .selected(cellIndex) _selectedSegment = .selected(UInt(cellIndex))
highlightCell(cellIndex: cellIndex) highlightCell(cellIndex: cellIndex)
} }

@ -1,66 +0,0 @@
//
// ScrollingSegmentedControlAdapter.swift
// AlphaWallet
//
// Created by Jerome Chan on 28/12/21.
//
import UIKit
class ScrollableSegmentedControlAdapter: ScrollableSegmentedControl, ReusableTableHeaderViewType {
static func tokensSegmentControl(titles: [String]) -> ScrollableSegmentedControlAdapter {
let cellConfiguration = Style.ScrollableSegmentedControlCell.configuration
let controlConfiguration = Style.ScrollableSegmentedControl.configuration
let cells = titles.map { title in
ScrollableSegmentedControlCell(frame: .zero, title: title, configuration: cellConfiguration)
}
let control = ScrollableSegmentedControlAdapter(cells: cells, configuration: controlConfiguration)
control.dummyControl = SegmentedControl(titles: titles)
control.addTarget(control, action: #selector(handleTap(_:)), for: .touchUpInside)
control.setSelection(cellIndex: 0)
return control
}
weak var delegate: SegmentedControlDelegate?
var dummyControl: SegmentedControl?
var selection: SegmentedControl.Selection = .unselected {
didSet {
handleSelection(selection)
}
}
override init(cells: [ScrollableSegmentedControlCell], configuration: ScrollableSegmentedControlConfiguration) {
super.init(cells: cells, configuration: configuration)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func handleTap(_ sender: ScrollableSegmentedControl) {
guard let delegate = delegate, let dummyControl = dummyControl else {
return
}
var selection: SegmentedControl.Selection
switch sender.selectedSegment {
case .unselected:
selection = .unselected
case .selected(let index):
selection = .selected(UInt(index))
}
delegate.didTapSegment(atSelection: selection, inSegmentedControl: dummyControl)
}
private func handleSelection(_ inputSelection: SegmentedControl.Selection) {
switch inputSelection {
case .unselected:
unselect()
case .selected(let index):
setSelection(cellIndex: Int(index))
}
}
}

@ -41,6 +41,7 @@ class SaveCustomRpcOverallViewController: UIViewController, SaveCustomRpcHandleU
private var browseViewController: SaveCustomRpcBrowseViewController private var browseViewController: SaveCustomRpcBrowseViewController
private var containerConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]() private var containerConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
private var entryViewController: SaveCustomRpcManualEntryViewController private var entryViewController: SaveCustomRpcManualEntryViewController
private var selection: ControlSelection = .selected(UInt(SaveCustomRpcOverallTab.browse.position))
// MARK: Public // MARK: Public
@ -116,7 +117,8 @@ class SaveCustomRpcOverallViewController: UIViewController, SaveCustomRpcHandleU
// MARK: - Configuration // MARK: - Configuration
private func configureViewController() { private func configureViewController() {
overallView.delegate = self overallView.segmentedControl.addTarget(self, action: #selector(handleTap(_:)), for: .touchUpInside)
overallView.segmentedControl.setSelection(cellIndex: SaveCustomRpcOverallTab.browse.position)
browseViewController.searchDelegate = self browseViewController.searchDelegate = self
searchController.searchResultsUpdater = browseViewController searchController.searchResultsUpdater = browseViewController
searchController.delegate = self searchController.delegate = self
@ -128,7 +130,7 @@ class SaveCustomRpcOverallViewController: UIViewController, SaveCustomRpcHandleU
} }
private func activateCurrentViewController() { private func activateCurrentViewController() {
switch overallView.segmentedControl.selection { switch selection {
case .selected(let tab) where tab == SaveCustomRpcOverallTab.browse.position: case .selected(let tab) where tab == SaveCustomRpcOverallTab.browse.position:
activateBrowseViewController() activateBrowseViewController()
case .selected(let tab) where tab == SaveCustomRpcOverallTab.manual.position: case .selected(let tab) where tab == SaveCustomRpcOverallTab.manual.position:
@ -239,6 +241,18 @@ class SaveCustomRpcOverallViewController: UIViewController, SaveCustomRpcHandleU
}.startAnimation() }.startAnimation()
} }
// MARK: - ObjC handlers
@objc func handleTap(_ sender: ScrollableSegmentedControl) {
switch sender.selectedSegment {
case .unselected:
selection = .unselected
case .selected(let index):
selection = .selected(UInt(index))
}
activateCurrentViewController()
}
} }
// MARK: - Passthrough to manualViewController // MARK: - Passthrough to manualViewController
@ -251,18 +265,6 @@ extension SaveCustomRpcOverallViewController {
} }
// MARK: - SegmentedControlDelegate
extension SaveCustomRpcOverallViewController: SegmentedControlDelegate {
func didTapSegment(atSelection selection: SegmentedControl.Selection, inSegmentedControl segmentedControl: SegmentedControl) {
guard segmentedControl.selection != selection else { return }
segmentedControl.selection = selection
activateCurrentViewController()
}
}
// MARK: - SaveCustomRpcBrowseViewControllerDelegate // MARK: - SaveCustomRpcBrowseViewControllerDelegate
extension SaveCustomRpcOverallViewController: SaveCustomRpcBrowseViewControllerSearchDelegate { extension SaveCustomRpcOverallViewController: SaveCustomRpcBrowseViewControllerSearchDelegate {

@ -11,16 +11,15 @@ class SaveCustomRpcOverallView: UIView {
let titles: [String] let titles: [String]
weak var delegate: SegmentedControlDelegate? {
didSet {
segmentedControl.delegate = self.delegate
}
}
var bottomConstraint: NSLayoutConstraint? var bottomConstraint: NSLayoutConstraint?
lazy var segmentedControl: SegmentedControl = { lazy var segmentedControl: ScrollableSegmentedControl = {
let segmentedControl = SegmentedControl(titles: titles, alignment: .center, distribution: .fillEqually) let cellConfiguration = Style.ScrollableSegmentedControlCell.configuration
let controlConfiguration = Style.ScrollableSegmentedControl.configuration
let cells = titles.map { title in
ScrollableSegmentedControlCell(frame: .zero, title: title, configuration: cellConfiguration)
}
let segmentedControl = ScrollableSegmentedControl(cells: cells, configuration: controlConfiguration)
segmentedControl.translatesAutoresizingMaskIntoConstraints = false segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.heightAnchor.constraint(equalToConstant: 50.0).isActive = true segmentedControl.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
return segmentedControl return segmentedControl

@ -310,7 +310,7 @@ extension AddHideTokensViewController: UITableViewDelegate {
} }
extension AddHideTokensViewController: DropDownViewDelegate { extension AddHideTokensViewController: DropDownViewDelegate {
func filterDropDownViewDidChange(selection: SegmentedControl.Selection) { func filterDropDownViewDidChange(selection: ControlSelection) {
guard let filterParam = tokenFilterView.value(from: selection) else { return } guard let filterParam = tokenFilterView.value(from: selection) else { return }
viewModel.sortTokensParam = filterParam viewModel.sortTokensParam = filterParam

@ -90,7 +90,16 @@ class TokensViewController: UIViewController {
} }
private let sessions: ServerDictionary<WalletSession> private let sessions: ServerDictionary<WalletSession>
private let account: Wallet private let account: Wallet
lazy private var tableViewFilterView = ScrollableSegmentedControlAdapter.tokensSegmentControl(titles: TokensViewModel.segmentedControlTitles) lazy private var tableViewFilterView: ScrollableSegmentedControl = {
let cellConfiguration = Style.ScrollableSegmentedControlCell.configuration
let controlConfiguration = Style.ScrollableSegmentedControl.configuration
let cells = TokensViewModel.segmentedControlTitles.map { title in
ScrollableSegmentedControlCell(frame: .zero, title: title, configuration: cellConfiguration)
}
let control = ScrollableSegmentedControl(cells: cells, configuration: controlConfiguration)
control.setSelection(cellIndex: 0)
return control
}()
private lazy var emptyTableView: EmptyTableView = { private lazy var emptyTableView: EmptyTableView = {
let view = EmptyTableView(title: "", image: R.image.activities_empty_list()!, heightAdjustment: 0) let view = EmptyTableView(title: "", image: R.image.activities_empty_list()!, heightAdjustment: 0)
view.translatesAutoresizingMaskIntoConstraints = false view.translatesAutoresizingMaskIntoConstraints = false
@ -107,7 +116,7 @@ class TokensViewController: UIViewController {
tableView.register(OpenSeaNonFungibleTokenPairTableCell.self) tableView.register(OpenSeaNonFungibleTokenPairTableCell.self)
tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<UISearchBar>.self) tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<UISearchBar>.self)
tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<ScrollableSegmentedControlAdapter>.self) tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<ScrollableSegmentedControl>.self)
tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<AddHideTokensView>.self) tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<AddHideTokensView>.self)
tableView.registerHeaderFooterView(ActiveWalletSessionView.self) tableView.registerHeaderFooterView(ActiveWalletSessionView.self)
tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<WalletSummaryView>.self) tableView.registerHeaderFooterView(GeneralTableViewSectionHeader<WalletSummaryView>.self)
@ -276,7 +285,7 @@ class TokensViewController: UIViewController {
view.backgroundColor = viewModel.backgroundColor view.backgroundColor = viewModel.backgroundColor
tableViewFilterView.delegate = self tableViewFilterView.addTarget(self, action: #selector(didTapSegment(_:)), for: .touchUpInside)
tableViewFilterView.translatesAutoresizingMaskIntoConstraints = false tableViewFilterView.translatesAutoresizingMaskIntoConstraints = false
consoleButton.addTarget(self, action: #selector(openConsole), for: .touchUpInside) consoleButton.addTarget(self, action: #selector(openConsole), for: .touchUpInside)
@ -466,7 +475,7 @@ extension TokensViewController: UITableViewDelegate {
return header return header
case .filters: case .filters:
let header: TokensViewController.GeneralTableViewSectionHeader<ScrollableSegmentedControlAdapter> = tableView.dequeueReusableHeaderFooterView() let header: TokensViewController.GeneralTableViewSectionHeader<ScrollableSegmentedControl> = tableView.dequeueReusableHeaderFooterView()
header.subview = tableViewFilterView header.subview = tableViewFilterView
header.useSeparatorLine = false header.useSeparatorLine = false
@ -686,20 +695,20 @@ extension TokensViewController: AddHideTokensViewDelegate {
} }
} }
extension TokensViewController: SegmentedControlDelegate { extension TokensViewController {
func didTapSegment(atSelection selection: SegmentedControl.Selection, inSegmentedControl segmentedControl: SegmentedControl) { @objc func didTapSegment(_ control: ScrollableSegmentedControl) {
guard let filter = viewModel.convertSegmentedControlSelectionToFilter(selection) else { return } guard let filter = viewModel.convertSegmentedControlSelectionToFilter(control.selectedSegment) else { return }
apply(filter: filter, withSegmentAtSelection: selection) apply(filter: filter, withSegmentAtSelection: control.selectedSegment)
} }
private func apply(filter: WalletFilter, withSegmentAtSelection selection: SegmentedControl.Selection?) { private func apply(filter: WalletFilter, withSegmentAtSelection selection: ControlSelection?) {
let previousFilter = viewModel.filter let previousFilter = viewModel.filter
viewModel.filter = filter viewModel.filter = filter
reload() reload()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
//Important to update the segmented control (and hence add the segmented control back to the table) after they have been re-added to the table header through the table reload. Otherwise adding to the table header will break the animation for segmented control //Important to update the segmented control (and hence add the segmented control back to the table) after they have been re-added to the table header through the table reload. Otherwise adding to the table header will break the animation for segmented control
if let selection = selection { if let selection = selection, case let ControlSelection.selected(index) = selection {
self.tableViewFilterView.selection = selection self.tableViewFilterView.setSelection(cellIndex: Int(index))
} }
} }
//Exit search if user tapped on the wallet filter. Careful to not trigger an infinite recursion between changing the filter by "category" and search keywords which are all based on filters //Exit search if user tapped on the wallet filter. Careful to not trigger an infinite recursion between changing the filter by "category" and search keywords which are all based on filters
@ -756,7 +765,7 @@ extension TokensViewController: UISearchResultsUpdating {
} }
private func updateResults(withKeyword keyword: String) { private func updateResults(withKeyword keyword: String) {
tableViewFilterView.selection = .unselected tableViewFilterView.unselect()
apply(filter: .keyword(keyword), withSegmentAtSelection: nil) apply(filter: .keyword(keyword), withSegmentAtSelection: nil)
} }

@ -1,56 +0,0 @@
// Copyright © 2020 Stormbird PTE. LTD.
import UIKit
struct SegmentedControlViewModel {
var selection: SegmentedControl.Selection
init(selection: SegmentedControl.Selection) {
self.selection = selection
}
var backgroundColor: UIColor {
return Colors.appBackground
}
func titleFont(forSelection selection: SegmentedControl.Selection) -> UIFont {
if selection == self.selection {
return selectedTitleFont
} else {
return unselectedTitleFont
}
}
func titleColor(forSelection selection: SegmentedControl.Selection) -> UIColor {
if selection == self.selection {
return selectedTitleColor
} else {
return unselectedTitleColor
}
}
private var unselectedTitleFont: UIFont {
return Fonts.regular(size: 15)
}
private var selectedTitleFont: UIFont {
return Fonts.semibold(size: 15)
}
private var unselectedTitleColor: UIColor {
return R.color.dove()!
}
private var selectedTitleColor: UIColor {
return selectedBarColor
}
var unselectedBarColor: UIColor {
return Style.SegmentedControl.Separator.color
// return R.color.alto()!
}
var selectedBarColor: UIColor {
return Colors.appTint
}
}

@ -226,7 +226,7 @@ class TokensViewModel {
return tokens.first(where: { $0.primaryKey == TokensDataStore.etherToken(forServer: server).primaryKey }) return tokens.first(where: { $0.primaryKey == TokensDataStore.etherToken(forServer: server).primaryKey })
} }
func convertSegmentedControlSelectionToFilter(_ selection: SegmentedControl.Selection) -> WalletFilter? { func convertSegmentedControlSelectionToFilter(_ selection: ControlSelection) -> WalletFilter? {
switch selection { switch selection {
case .selected(let index): case .selected(let index):
return WalletFilter.filter(fromIndex: index) return WalletFilter.filter(fromIndex: index)

@ -1,176 +0,0 @@
// Copyright © 2020 Stormbird PTE. LTD.
import UIKit
protocol SegmentedControlDelegate: AnyObject {
//Implementations of this protocol function will have to cast `segment` to the appropriate type. Maybe some generic or associated type magic can fix this, but alas time constraints
func didTapSegment(atSelection selection: SegmentedControl.Selection, inSegmentedControl segmentedControl: SegmentedControl)
}
extension SegmentedControl {
static func tokensSegmentControl(titles: [String]) -> SegmentedControl {
let isNarrowScreen = ScreenChecker().isNarrowScreen
let spacing: CGFloat = isNarrowScreen ? 30 : 40
let inset: CGFloat = isNarrowScreen ? 7 : 20
return .init(titles: titles, segmentConfiguration: .init(spacing: spacing, selectionIndicatorInsets: .init(top: 0, left: inset, bottom: 0, right: inset), selectionBarHeight: 3, barHeight: 1))
}
}
class SegmentedControl: UIView, ReusableTableHeaderViewType {
enum Alignment {
case left
case right
case center
}
enum Selection: Equatable {
case selected(UInt)
case unselected
}
private let buttons: [UIButton]
private let highlightedBar = UIView()
private var highlightBarHorizontalConstraints: [NSLayoutConstraint]?
private lazy var viewModel = SegmentedControlViewModel(selection: selection)
weak var delegate: SegmentedControlDelegate?
var selection: Selection = .selected(0) {
didSet {
if oldValue == selection { return }
viewModel.selection = selection
configureTitleButtons()
configureHighlightedBar()
}
}
struct SegmentConfiguration {
var spacing: CGFloat = 20
var selectionIndicatorInsets: UIEdgeInsets = .init(top: 0, left: 7, bottom: 0, right: 7)
var selectionBarHeight: CGFloat = 3
var barHeight: CGFloat = 1
}
private let segmentConfiguration: SegmentConfiguration
init(titles: [String], alignment: Alignment = .left, distribution: UIStackView.Distribution = .fill, segmentConfiguration: SegmentConfiguration = .init()) {
self.buttons = SegmentedControl.createButtons(fromTitles: titles)
self.segmentConfiguration = segmentConfiguration
super.init(frame: .zero)
backgroundColor = viewModel.backgroundColor
for each in buttons {
each.addTarget(self, action: #selector(segmentTapped), for: .touchUpInside)
}
let buttonsStackView = buttons.map { $0 as UIView }.asStackView(distribution: distribution, spacing: segmentConfiguration.spacing)
buttonsStackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(buttonsStackView)
let fullWidthBar = UIView()
fullWidthBar.translatesAutoresizingMaskIntoConstraints = false
fullWidthBar.backgroundColor = viewModel.unselectedBarColor
addSubview(fullWidthBar)
highlightedBar.translatesAutoresizingMaskIntoConstraints = false
fullWidthBar.addSubview(highlightedBar)
let barHeightConstraint = fullWidthBar.heightAnchor.constraint(equalToConstant: segmentConfiguration.barHeight)
barHeightConstraint.priority = .defaultHigh
var contraints: [NSLayoutConstraint] = []
switch alignment {
case .left:
let stackViewLeadingConstraint = buttonsStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 17)
stackViewLeadingConstraint.priority = .defaultHigh
let stackViewWidthConstraint = buttonsStackView.widthAnchor.constraint(lessThanOrEqualTo: widthAnchor, constant: -17)
stackViewWidthConstraint.priority = .defaultHigh
contraints = [stackViewLeadingConstraint, stackViewWidthConstraint]
case .center:
let stackViewCenterConstraint = buttonsStackView.centerXAnchor.constraint(equalTo: centerXAnchor)
stackViewCenterConstraint.priority = .defaultHigh
let stackViewWidthConstraint = buttonsStackView.widthAnchor.constraint(equalTo: widthAnchor, constant: -34)
stackViewWidthConstraint.priority = .defaultHigh
contraints = [stackViewCenterConstraint, stackViewWidthConstraint]
case .right:
let stackViewLeadingConstraint = buttonsStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -17)
stackViewLeadingConstraint.priority = .defaultHigh
let stackViewWidthConstraint = buttonsStackView.widthAnchor.constraint(lessThanOrEqualTo: widthAnchor, constant: -17)
stackViewWidthConstraint.priority = .defaultHigh
contraints = [stackViewLeadingConstraint, stackViewWidthConstraint]
}
NSLayoutConstraint.activate(contraints + [
buttonsStackView.topAnchor.constraint(equalTo: topAnchor),
buttonsStackView.bottomAnchor.constraint(equalTo: fullWidthBar.topAnchor),
fullWidthBar.leadingAnchor.constraint(equalTo: leadingAnchor),
fullWidthBar.trailingAnchor.constraint(equalTo: trailingAnchor),
barHeightConstraint,
fullWidthBar.bottomAnchor.constraint(equalTo: bottomAnchor),
highlightedBar.heightAnchor.constraint(equalToConstant: segmentConfiguration.selectionBarHeight),
highlightedBar.bottomAnchor.constraint(equalTo: fullWidthBar.bottomAnchor),
])
configureTitleButtons()
configureHighlightedBar()
}
required init?(coder aDecoder: NSCoder) {
return nil
}
private static func createButtons(fromTitles titles: [String]) -> [UIButton] {
return titles.map {
let button = UIButton(type: .system)
button.setTitle($0, for: .normal)
return button
}
}
@objc private func segmentTapped(_ source: UIButton) {
guard let segment = buttons.firstIndex(of: source).flatMap({ UInt($0) }) else { return }
delegate?.didTapSegment(atSelection: .selected(segment), inSegmentedControl: self)
}
func configureTitleButtons() {
for (index, each) in buttons.enumerated() {
//This is safe only because index can't possibly be negative
let index = UInt(index)
each.setTitleColor(viewModel.titleColor(forSelection: .selected(index)), for: .normal)
each.titleLabel?.font = viewModel.titleFont(forSelection: .selected(index))
}
}
func configureHighlightedBar() {
switch selection {
case .selected(let index):
highlightedBar.backgroundColor = viewModel.selectedBarColor
let index = Int(index)
let button: UIButton = buttons[index]
if let previousConstraints = highlightBarHorizontalConstraints {
NSLayoutConstraint.deactivate(previousConstraints)
}
highlightBarHorizontalConstraints = [
highlightedBar.leadingAnchor.constraint(equalTo: button.leadingAnchor, constant: -segmentConfiguration.selectionIndicatorInsets.left),
highlightedBar.trailingAnchor.constraint(equalTo: button.trailingAnchor, constant: segmentConfiguration.selectionIndicatorInsets.right),
]
if let constraints = highlightBarHorizontalConstraints {
NSLayoutConstraint.activate(constraints)
}
UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 10, options: .allowUserInteraction, animations: {
self.layoutIfNeeded()
})
case .unselected:
highlightedBar.backgroundColor = nil
}
}
}

@ -177,7 +177,7 @@ class TokenHistoryChartView: UIView {
} }
extension TokenHistoryChartView: TokenHistoryPeriodSelectorViewDelegate { extension TokenHistoryChartView: TokenHistoryPeriodSelectorViewDelegate {
func view(_ view: TokenHistoryPeriodSelectorView, didChangeSelection selection: SegmentedControl.Selection) { func view(_ view: TokenHistoryPeriodSelectorView, didChangeSelection selection: ControlSelection) {
switch selection { switch selection {
case .selected(let index): case .selected(let index):
viewModel.selectedHistoryIndex = Int(index) viewModel.selectedHistoryIndex = Int(index)

@ -8,7 +8,7 @@
import UIKit import UIKit
protocol TokenHistoryPeriodSelectorViewDelegate: class { protocol TokenHistoryPeriodSelectorViewDelegate: class {
func view(_ view: TokenHistoryPeriodSelectorView, didChangeSelection selection: SegmentedControl.Selection) func view(_ view: TokenHistoryPeriodSelectorView, didChangeSelection selection: ControlSelection)
} }
struct TokenHistoryPeriodSelectorViewModel { struct TokenHistoryPeriodSelectorViewModel {
@ -23,7 +23,7 @@ struct TokenHistoryPeriodSelectorViewModel {
class TokenHistoryPeriodSelectorView: UIView { class TokenHistoryPeriodSelectorView: UIView {
private let controls: [UIButton] private let controls: [UIButton]
var selectedIndex: SegmentedControl.Selection { var selectedIndex: ControlSelection {
if let index = controls.firstIndex(where: { $0.isSelected }) { if let index = controls.firstIndex(where: { $0.isSelected }) {
return .selected(UInt(index)) return .selected(UInt(index))
} else { } else {

@ -18,12 +18,17 @@ protocol PagesContainerViewDelegate: class {
class PagesContainerView: RoundedBackground { class PagesContainerView: RoundedBackground {
private lazy var tabBar: SegmentedControl = { private lazy var tabBar: ScrollableSegmentedControl = {
let titles = pages.map { $0.title } let titles = pages.map { $0.title }
let control = SegmentedControl(titles: titles, alignment: .center, distribution: .fillEqually) let cellConfiguration = Style.ScrollableSegmentedControlCell.configuration
let controlConfiguration = Style.ScrollableSegmentedControl.configuration
let cells = titles.map { title in
ScrollableSegmentedControlCell(frame: .zero, title: title, configuration: cellConfiguration)
}
let control = ScrollableSegmentedControl(cells: cells, configuration: controlConfiguration)
control.setSelection(cellIndex: 0)
control.translatesAutoresizingMaskIntoConstraints = false control.translatesAutoresizingMaskIntoConstraints = false
control.delegate = self control.addTarget(self, action: #selector(didTapSegment(_:)), for: .touchUpInside)
return control return control
}() }()
@ -47,8 +52,8 @@ class PagesContainerView: RoundedBackground {
let pages: [PageViewType] let pages: [PageViewType]
weak var delegate: PagesContainerViewDelegate? weak var delegate: PagesContainerViewDelegate?
var selection: SegmentedControl.Selection { var selection: ControlSelection {
return tabBar.selection return tabBar.selectedSegment
} }
private (set) var bottomAnchorConstraints: [NSLayoutConstraint] = [] private (set) var bottomAnchorConstraints: [NSLayoutConstraint] = []
@ -94,14 +99,10 @@ class PagesContainerView: RoundedBackground {
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
return nil return nil
} }
}
extension PagesContainerView: SegmentedControlDelegate {
func didTapSegment(atSelection selection: SegmentedControl.Selection, inSegmentedControl segmentedControl: SegmentedControl) { @objc func didTapSegment(_ control: ScrollableSegmentedControl) {
tabBar.selection = selection
let index: Int let index: Int
switch selection { switch control.selectedSegment {
case .selected(let value): case .selected(let value):
index = Int(value) index = Int(value)
case .unselected: case .unselected:

@ -25,7 +25,16 @@ class ImportWalletViewController: UIViewController {
//We don't actually use the rounded corner here, but it's a useful "content" view here //We don't actually use the rounded corner here, but it's a useful "content" view here
private let roundedBackground = RoundedBackground() private let roundedBackground = RoundedBackground()
private let scrollView = UIScrollView() private let scrollView = UIScrollView()
private let tabBar = SegmentedControl(titles: ImportWalletViewModel.segmentedControlTitles) private let tabBar: ScrollableSegmentedControl = {
let cellConfiguration = Style.ScrollableSegmentedControlCell.configuration
let controlConfiguration = Style.ScrollableSegmentedControl.configuration
let cells = ImportWalletViewModel.segmentedControlTitles.map { title in
ScrollableSegmentedControlCell(frame: .zero, title: title, configuration: cellConfiguration)
}
let control = ScrollableSegmentedControl(cells: cells, configuration: controlConfiguration)
control.setSelection(cellIndex: 0)
return control
}()
private let mnemonicCountLabel: UILabel = { private let mnemonicCountLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false label.translatesAutoresizingMaskIntoConstraints = false
@ -176,7 +185,7 @@ class ImportWalletViewController: UIViewController {
scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.translatesAutoresizingMaskIntoConstraints = false
roundedBackground.addSubview(scrollView) roundedBackground.addSubview(scrollView)
tabBar.delegate = self tabBar.addTarget(self, action: #selector(didTapSegment(_:)), for: .touchUpInside)
tabBar.translatesAutoresizingMaskIntoConstraints = false tabBar.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tabBar) view.addSubview(tabBar)
@ -283,8 +292,12 @@ class ImportWalletViewController: UIViewController {
keyboardChecker.viewWillDisappear() keyboardChecker.viewWillDisappear()
} }
@objc func didTapSegment(_ control: ScrollableSegmentedControl) {
showCorrectTab()
}
private func showCorrectTab() { private func showCorrectTab() {
guard let tab = viewModel.convertSegmentedControlSelectionToFilter(tabBar.selection) else { return } guard let tab = viewModel.convertSegmentedControlSelectionToFilter(tabBar.selectedSegment) else { return }
switch tab { switch tab {
case .mnemonic: case .mnemonic:
showMnemonicControlsOnly() showMnemonicControlsOnly()
@ -298,8 +311,7 @@ class ImportWalletViewController: UIViewController {
} }
func showWatchTab() { func showWatchTab() {
//TODO shouldn't this be done in a view model? tabBar.setSelection(cellIndex: Int(ImportWalletTab.watch.selectionIndex))
tabBar.selection = .selected(ImportWalletTab.watch.selectionIndex)
showCorrectTab() showCorrectTab()
} }
@ -355,7 +367,7 @@ class ImportWalletViewController: UIViewController {
///Returns true only if valid ///Returns true only if valid
private func validate() -> Bool { private func validate() -> Bool {
guard let tab = viewModel.convertSegmentedControlSelectionToFilter(tabBar.selection) else { return false } guard let tab = viewModel.convertSegmentedControlSelectionToFilter(tabBar.selectedSegment) else { return false }
switch tab { switch tab {
case .mnemonic: case .mnemonic:
return validateMnemonic() return validateMnemonic()
@ -429,7 +441,7 @@ class ImportWalletViewController: UIViewController {
displayLoading(text: R.string.localizable.importWalletImportingIndicatorLabelTitle(), animated: false) displayLoading(text: R.string.localizable.importWalletImportingIndicatorLabelTitle(), animated: false)
let importTypeOptional: ImportType? = { let importTypeOptional: ImportType? = {
guard let tab = viewModel.convertSegmentedControlSelectionToFilter(tabBar.selection) else { return nil } guard let tab = viewModel.convertSegmentedControlSelectionToFilter(tabBar.selectedSegment) else { return nil }
switch tab { switch tab {
case .mnemonic: case .mnemonic:
return .mnemonic(words: mnemonicInput, password: "") return .mnemonic(words: mnemonicInput, password: "")
@ -514,11 +526,11 @@ class ImportWalletViewController: UIViewController {
} }
func set(tabSelection selection: ImportWalletTab) { func set(tabSelection selection: ImportWalletTab) {
tabBar.selection = .selected(selection.selectionIndex) tabBar.setSelection(cellIndex: Int(selection.selectionIndex))
} }
func setValueForCurrentField(string: String) { func setValueForCurrentField(string: String) {
switch viewModel.convertSegmentedControlSelectionToFilter(tabBar.selection) { switch viewModel.convertSegmentedControlSelectionToFilter(tabBar.selectedSegment) {
case .mnemonic: case .mnemonic:
mnemonicTextView.value = string mnemonicTextView.value = string
case .keystore: case .keystore:
@ -717,13 +729,6 @@ extension ImportWalletViewController: AddressTextFieldDelegate {
} }
} }
extension ImportWalletViewController: SegmentedControlDelegate {
func didTapSegment(atSelection selection: SegmentedControl.Selection, inSegmentedControl segmentedControl: SegmentedControl) {
tabBar.selection = selection
showCorrectTab()
}
}
extension ImportWalletViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { extension ImportWalletViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
mnemonicSuggestions.count mnemonicSuggestions.count

@ -49,10 +49,10 @@ struct ImportWalletViewModel {
]) ])
} }
func convertSegmentedControlSelectionToFilter(_ selection: SegmentedControl.Selection) -> ImportWalletTab? { func convertSegmentedControlSelectionToFilter(_ selection: ControlSelection) -> ImportWalletTab? {
switch selection { switch selection {
case .selected(let index): case .selected(let index):
return ImportWalletTab.filter(fromIndex: index) return ImportWalletTab.filter(fromIndex: UInt(index))
case .unselected: case .unselected:
return nil return nil
} }

Loading…
Cancel
Save